/// <summary> /// Stops message sending to a given client /// </summary> public static void DisableClient(this SignalX signalX, string clientMethodName) { string correlationId = Guid.NewGuid().ToString(); signalX.Advanced.Trace(correlationId, $"Disabling client {clientMethodName}..."); UpdateClient(signalX, correlationId, clientMethodName, true); }
internal SignalXRequest( string correlationId, SignalX signalX, string replyTo, object sender, string messageId, string message, string user, string handler, IPrincipal principalUser, List <string> groups, IRequest request, HubCallerContext context, IHubCallerConnectionContext <dynamic> clients, IGroupManager groupsManager, object messageObject) { this.CorrelationId = correlationId; this.Context = context; this.Clients = clients; this.GroupsManager = groupsManager; this.SignalX = signalX ?? throw new ArgumentNullException(nameof(signalX)); this.ReplyTo = replyTo; this.Sender = sender; this.MessageId = messageId; this.MessageAsJson = message; //UserId = principalUser?.Identity?.Name; this.User = user; this.Handler = handler; this.PrincipalUser = principalUser; this.Groups = groups ?? new List <string>(); this.Request = request; this.MessageObject = messageObject; }
/// <summary> /// Runs when client is ready before client's ready functions executes /// </summary> /// <param name="signalX"></param> /// <param name="onResponse"></param> public static void OnClientReady(this SignalX signalX, Action onResponse) { if (onResponse != null) { signalX.Advanced.Trace(signalX.AppCorrelationId, "Setting up OnClientReady ..."); signalX.OnClientReady.Add(r => { onResponse?.Invoke(); }); } }
public static async Task RespondToScriptRequest( this SignalX signalX, string correlationId, HubCallerContext context, IHubCallerConnectionContext <dynamic> clients, IGroupManager groups) { signalX.Advanced.Trace(correlationId, "Preparing script for client ..."); signalX.Settings.ConnectionEventsHandler.ForEach(h => h?.Invoke(ConnectionEvents.SignalXRequestForMethods.ToString(), context?.User?.Identity?.Name)); if (!await signalX.CanProcess(correlationId, context, "", null, true).ConfigureAwait(false)) { signalX.Settings.WarningHandler.ForEach(h => h?.Invoke("RequireAuthentication", "User attempting to connect has not been authenticated when authentication is required")); return; } string logRequestOnClient = signalX.Settings.LogAgentMessagesOnClient ? signalX.Settings.ClientLogScriptFunction + "(message);" : ""; string logResponseOnClient = signalX.Settings.LogAgentMessagesOnClient ? signalX.Settings.ClientLogScriptFunction + "(response);" : ""; string receiveErrorsFromClient = (signalX.Settings.ReceiveErrorMessagesFromClient ? signalX.ClientErrorSnippet : "") + (signalX.Settings.ReceiveDebugMessagesFromClient ? signalX.ClientDebugSnippet : ""); string clientAgent = @" " + receiveErrorsFromClient + @" signalx.client." + SignalX.SIGNALXCLIENTAGENT + @" = function (message) { " + logRequestOnClient + @" var response ={}; try{ response={ Error : '', MessageAsJsonString : JSON.stringify(eval('(function(){ '+message+' })()')) }; }catch(err){ response = {Error : err, MessageAsJsonString :'' }; signalx.error.f({error:err,description:'error occured while evaluating server agent command',context:'server agent error context'}); } " + logResponseOnClient + @" signalx.server." + SignalX.SIGNALXCLIENTAGENT + @"(response,function(messageResponse){ }); };"; string clientReady = signalX.OnClientReady.Count == 0 ? "" : @" signalx.beforeOthersReady=function(f){ signalx.debug.f('Checking with server before executing ready functions...') signalx.server." + SignalX.SIGNALXCLIENTREADY + @"('',function(){ signalx.debug.f('Server indicates readiness. Now running client ready functions ... '); typeof f ==='function' && f(); }); }"; string methods = "; window.signalxidgen=window.signalxidgen||function(){return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); return v.toString(16);})};" + signalX.SignalXServers.Aggregate(clientReady + clientAgent + "var $sx= {", (current, signalXServer) => current + signalXServer.Key + @":function(m,repTo,sen,msgId){ var deferred = $.Deferred(); window.signalxid=window.signalxid||window.signalxidgen(); sen=sen||window.signalxid;repTo=repTo||''; var messageId=signalx.MESSAGE_ID || window.signalxidgen(); var rt=repTo; if(typeof repTo==='function'){ signalx.waitingList(messageId,repTo);rt=messageId; } if(!repTo){ signalx.waitingList(messageId,deferred);rt=messageId; } var messageToSend={handler:'" + signalXServer.Key + "',message:m, replyTo:rt,sender:sen, groupList:signalx.groupList}; chat.server.send('" + signalXServer.Key + "',(m && JSON.stringify(m)) ||'',rt,sen,messageId,signalx.groupList||[]); if(repTo){return messageId}else{ return deferred.promise();} },").Trim() + "}; $sx; "; if (signalX.Settings.StartCountingInComingMessages) { Interlocked.Increment(ref signalX.Settings.InComingCounter); } signalX.Advanced.Trace(correlationId, "Sending script to client ..."); signalX.Receiver.ReceiveScripts(correlationId, context?.ConnectionId, methods, context, groups, clients); signalX.Settings.ConnectionEventsHandler.ForEach(h => h?.Invoke(ConnectionEvents.SignalXRequestForMethodsCompleted.ToString(), methods)); }
public static void EnableAllClients(this SignalX signalX) { signalX.Advanced.Trace(signalX.AppCorrelationId, "Enabling all clients ..."); signalX.Settings.DisabledAllClients = false; foreach (string s in signalX.SignalXClientDetails.Select(x => x.Key).ToList()) { signalX.UpdateClient(signalX.AppCorrelationId, s, false); } }
internal static async Task <bool> CanProcess(this SignalX signalX, string correlationId, HubCallerContext context, string serverHandlerName, SignalXRequest request, bool isScriptRequest) { signalX.Advanced.Trace(correlationId, $"Checking if request can be processed for {serverHandlerName}..."); bool result = false; if (isScriptRequest) { signalX.Advanced.Trace(correlationId, $"Its a script request so no further checks are necessary for {serverHandlerName}..."); return(true); } if (signalX.SignalXServerExecutionDetails.ContainsKey(serverHandlerName)) { List <string> allowedGroups = signalX.SignalXServerExecutionDetails[serverHandlerName].AllowedGroups; signalX.Advanced.Trace(correlationId, $"Checking if request is coming from a client with group allowed to access server {serverHandlerName}..."); foreach (string allowedGroup in allowedGroups) { if (!request.Groups.Contains(allowedGroup)) { signalX.Settings.ConnectionEventsHandler.ForEach(h => h?.Invoke(ConnectionEvents.SignalXRequestAuthorizationFailed.ToString(), $"Authorization failed : The request does not contain group {allowedGroup} and is therefore denied access to {serverHandlerName}")); return(false); } } } if (signalX.Settings.RequireAuthorizationForAllHandlers || signalX.SignalXServerExecutionDetails.ContainsKey(serverHandlerName) && signalX.SignalXServerExecutionDetails[serverHandlerName].RequiresAuthorization) { signalX.Advanced.Trace(correlationId, $"Checking if request is authorized to access the server {serverHandlerName} because authorization function has been set ..."); if (signalX.Settings.AuthenticatedWhen != null) { result = await signalX.IsAuthenticated(correlationId, context.Request, request).ConfigureAwait(false); } else { result = context.User.Identity.IsAuthenticated; if (!result) { signalX.Settings.ConnectionEventsHandler.ForEach(h => h?.Invoke(ConnectionEvents.SignalXRequestAuthorizationFailed.ToString(), "Authorization failed after checking with context.User.Identity.IsAuthenticated. Custom Authorization check is not yet setup ")); } } } else { signalX.Settings.WarningHandler.ForEach(h => h?.Invoke("AuthorizationNotSet", "Try setting an authorization handler to prevent anonymous access into your server")); result = true; } signalX.Advanced.Trace(correlationId, $"request allowed to access the server {serverHandlerName} : {request}"); return(result); }
public static void DisableAllClients(this SignalX signalX, string correlationId = null) { correlationId = correlationId ?? Guid.NewGuid().ToString(); signalX.Advanced.Trace(correlationId, "Disabling all clients ..."); signalX.Settings.DisabledAllClients = true; foreach (string s in signalX.SignalXClientDetails.Select(x => x.Key).ToList()) { signalX.UpdateClient(correlationId, s, true); } }
public static void Server(this SignalX signalX, ServerType serverType, string name, Action <SignalXRequest> server, List <string> groupNames = null) { signalX.ServerBase( serverType, name, (r, s) => { server(r); return(Task.FromResult(true)); }, groupNames); }
/// <summary> /// Cookie authentication supported /// </summary> //public static void AuthenticationHandler(string cookieName, Func<Cookie,string, string, IRequest, bool> handler) //{ // AuthenticationCookieName = cookieName ?? throw new ArgumentNullException(nameof(cookieName)); // AuthenticatedWhen = handler ?? throw new ArgumentNullException(nameof(handler)); //} public static void AuthenticationHandler(this SignalX signalX, Func <SignalXRequest, Task <bool> > handler) { if (handler == null) { throw new ArgumentNullException(nameof(handler)); } signalX.Advanced.Trace(signalX.AppCorrelationId, "Setting up AuthenticationHandler ..."); signalX.Settings.AuthenticationCookieName = null; signalX.Settings.AuthenticatedWhen = handler; }
internal static void LeaveGroup( this SignalX signalX, string correlationId, HubCallerContext context, IHubCallerConnectionContext <dynamic> clients, IGroupManager groups, string groupName) { signalX.Advanced.Trace(correlationId, $"User {context?.ConnectionId} is leaving group {groupName}..."); groups.Remove(context?.ConnectionId, groupName); signalX.Settings.ConnectionEventsHandler.ForEach(h => h?.Invoke(ConnectionEvents.SignalXGroupLeave.ToString(), groupName)); signalX.Receiver.ReceiveInGroupManager(correlationId, "leave", context?.ConnectionId, groupName, context, clients, groups); }
/// <summary> /// Reply to every other clients but the sender /// </summary> /// <param name="signalX"></param> /// <param name="excludedUserId"></param> /// <param name="name"></param> /// <param name="data"></param> /// <param name="groupName"></param> public static void RespondToOthers(this SignalX signalX, string excludedUserId, string name, object data, string groupName = null, string correlationId = null) { if (!signalX.AllowToSend(name, data, correlationId)) { return; } if (signalX.Settings.StartCountingOutGoingMessages) { Interlocked.Increment(ref signalX.Settings.OutGoingCounter); } signalX.Receiver.ReceiveAsOther(correlationId, name, data, excludedUserId, groupName); }
/// <summary> /// Reply to a specific client /// </summary> /// <param name="signalX"></param> /// <param name="user"></param> /// <param name="name"></param> /// <param name="data"></param> public static void RespondToUser(this SignalX signalX, string user, string name, object data, string correlationId = null) { correlationId = correlationId ?? Guid.NewGuid().ToString(); if (!signalX.AllowToSend(name, data, correlationId)) { return; } if (signalX.Settings.StartCountingOutGoingMessages) { Interlocked.Increment(ref signalX.Settings.OutGoingCounter); } signalX.Receiver.Receive(user, name, data, correlationId); }
public static async Task <double> GetInComingMessageSpeedAsync(this SignalX signalX, TimeSpan duration) { signalX.Settings.InComingCounter = 0; var sw = new Stopwatch(); signalX.Settings.StartCountingInComingMessages = true; sw.Start(); await Task.Delay(duration); // might not be 5 sec signalX.Settings.StartCountingInComingMessages = false; sw.Stop(); long currentCount = Interlocked.Read(ref signalX.Settings.InComingCounter); return(currentCount / sw.Elapsed.TotalSeconds); }
/// <summary> /// Adds an exception handler /// </summary> /// <param name="signalX"></param> /// <param name="handler"></param> public static void OnException(this SignalX signalX, Action <string, Exception> handler) { signalX.Settings.ExceptionHandler.Add( (s, o) => { try { handler(s, o); } catch (Exception e) { //todo swallow } }); }
public static void RunJavaScriptOnUser(this SignalX signalX, string userId, string script, Action <ResponseAfterScriptRuns> onResponse = null, TimeSpan?delay = null) { signalX.Advanced.Trace(signalX.AppCorrelationId, $"Running javascript on user {userId} ..." + script); if (signalX.OnResponseAfterScriptRuns != null) { //todo do something here to maybe block multiple calls //todo before a previous one finishes //todo or throw a warning } delay = delay ?? TimeSpan.FromSeconds(0); signalX.OnResponseAfterScriptRuns = onResponse; Task.Delay(delay.Value).ContinueWith(c => { signalX.RespondToUser(userId, SignalX.SIGNALXCLIENTAGENT, script, signalX.AppCorrelationId); }); }
/// <summary> /// Adds a warning handler /// </summary> /// <param name="signalX"></param> /// <param name="handler"></param> public static void OnWarning(this SignalX signalX, Action <string, object> handler) { signalX.Settings.WarningHandler.Add( (s, o) => { try { handler(s, o); } catch (Exception e) { //todo swallow } }); }
/// <summary> /// Adds an exception handler /// </summary> /// <param name="signalX"></param> /// <param name="handler"></param> public static void OnException(this SignalX signalX, Action <Exception> handler) { signalX.Settings.ExceptionHandler.Add( (m, e) => { try { handler.Invoke(e); } catch (Exception exception) { //todo swallow } }); }
public void Add(SignalX SignalX, T key, string connectionId) { if (!SignalX.Settings.ManageUserConnections) { return; } HashSet <string> connections; if (!this._connections.TryGetValue(key, out connections)) { connections = new HashSet <string>(); this._connections.GetOrAdd(key, connections); } connections.Add(connectionId); }
internal static void UpdateClient(this SignalX signalX, string correlationId, string clientMethodName, bool status) { if (string.IsNullOrEmpty(clientMethodName)) { throw new ArgumentNullException(nameof(clientMethodName)); } if (signalX.SignalXClientDetails.ContainsKey(clientMethodName)) { signalX.SignalXClientDetails[clientMethodName].Disabled = status; } else { signalX.SignalXClientDetails.GetOrAdd(clientMethodName, new ClientDetails { Disabled = status }); } }
internal static async Task CallServer(this SignalX signalX, SignalXRequest request, string correlationId) { signalX.Advanced.Trace(correlationId, $"Running call to server {request?.Handler}..."); ServerHandlerDetails executionDetails = signalX.SignalXServerExecutionDetails[request.Handler]; if (executionDetails.IsSingleWriter) { using (executionDetails.SingleWriter.Write()) { await signalX.SignalXServers[request.Handler].Invoke(request, signalX.SignalXServerExecutionDetails[request.Handler].State).ConfigureAwait(false); } } else { await signalX.SignalXServers[request.Handler].Invoke(request, signalX.SignalXServerExecutionDetails[request.Handler].State).ConfigureAwait(false); } }
public void Remove(SignalX SignalX, T key, string connectionId) { if (!SignalX.Settings.ManageUserConnections) { return; } HashSet <string> connections; if (!this._connections.TryGetValue(key, out connections)) { return; } connections.Remove(connectionId); if (connections.Count == 0) { this._connections.TryRemove(key, out connections); } }
internal static async Task <bool> IsAuthenticated(this SignalX signalX, string correlationId, IRequest request, SignalXRequest sRequest) { bool result; try { //var cookie = request?.Cookies[AuthenticationCookieName]; //var ip = request?.Environment["server.RemoteIpAddress"]?.ToString(); result = await signalX.Settings.AuthenticatedWhen(sRequest).ConfigureAwait(false); if (!result) { signalX.Settings.ConnectionEventsHandler.ForEach(h => h?.Invoke(ConnectionEvents.SignalXRequestAuthorizationFailed.ToString(), "Authorization failed after checking with Custom Authorization provided")); } } catch (Exception e) { result = false; signalX.Settings.ConnectionEventsHandler.ForEach(h => h?.Invoke(ConnectionEvents.SignalXRequestAuthorizationFailed.ToString(), "Custom Authorization threw an exception " + e.Message)); signalX.Settings.ExceptionHandler.ForEach(h => h?.Invoke("Authentication failed", e)); } return(result); }
public static void RunJavaScriptOnAllClients(this SignalX signalX, string script, Action <ResponseAfterScriptRuns> onResponse = null, TimeSpan?delay = null) { signalX.RunJavaScriptOnAllClientsInGroup(script, null, onResponse, delay); }
public void RemoveAll(SignalX SignalX) { this._connections.Clear(); SignalX.Settings.HasOneOrMoreConnections = false; }
/// <summary> /// Adds a connection event handler /// </summary> /// <param name="signalX"></param> /// <param name="handler"></param> public static void OnConnectionEvent(this SignalX signalX, Action <string, object> handler) { signalX.Advanced.Trace(signalX.AppCorrelationId, "Setting up OnConnectionEvent ..."); signalX.Settings.ConnectionEventsHandler.Add(handler); }
public static void ServerAsync(this SignalX signalX, ServerType serverType, string name, Func <SignalXRequest, Task> server, List <string> groupNames = null) { signalX.ServerBase(serverType, name, (r, s) => server(r), groupNames); }
public static void ServerAsync(this SignalX signalX, string name, Func <SignalXRequest, SignalXServerState, Task> server, List <string> groupNames = null) { signalX.ServerBase(ServerType.Default, name, server, groupNames); }
/// <summary> /// Sets up a server /// </summary> /// <param name="signalX"></param> /// <param name="serverType"></param> /// <param name="name">A unique name for the server, unless dynamic server is allowed</param> /// <param name="server"></param> /// <param name="groupNames"></param> /// <param name="requireAuthorization"> /// Indicates if the set authorization should be checked before allowing access to the /// server /// </param> /// <param name="isSingleWriter">Set whether or not requests should be queued and only one allowed in at a time</param> /// <param name="allowDynamicServerForThisInstance"> /// Sets if it is allowed for another server to be created with same name. /// In such a case, the existing server will be discarded /// </param> internal static void ServerBase( this SignalX signalX, ServerType serverType, string name, Func <SignalXRequest, SignalXServerState, Task> server, List <string> groupNames = null ) { bool requireAuthorization = false; bool isSingleWriter = false; bool allowDynamicServerForThisInstance = false; switch (serverType) { case ServerType.Default: break; case ServerType.SingleAccess: isSingleWriter = true; break; case ServerType.Authorized: requireAuthorization = true; break; case ServerType.AuthorizedSingleAccess: requireAuthorization = true; isSingleWriter = true; break; case ServerType.Dynamic: allowDynamicServerForThisInstance = true; break; case ServerType.DynamicAuthorized: allowDynamicServerForThisInstance = true; requireAuthorization = true; break; default: throw new ArgumentOutOfRangeException(nameof(serverType), serverType, null); } signalX.Advanced.Trace(signalX.AppCorrelationId, $"Creating a server {name} with authorized groups {string.Join(",", groupNames ?? new List<string>())} and requires authorization : {requireAuthorization}, is set to single write : {isSingleWriter} and allows dynamic server for this instance {allowDynamicServerForThisInstance}"); groupNames = groupNames ?? new List <string>(); name = name.Trim(); string camelCased = char.ToLowerInvariant(name[0]) + name.Substring(1); string unCamelCased = char.ToUpperInvariant(name[0]) + name.Substring(1); if ((signalX.SignalXServers.ContainsKey(camelCased) || signalX.SignalXServers.ContainsKey(unCamelCased)) && !signalX.Settings.AllowDynamicServerInternal && !allowDynamicServerForThisInstance) { var exc = new Exception("Server with name '" + name + "' has already been created"); signalX.Advanced.Trace(signalX.AppCorrelationId, exc.Message, exc); throw exc; } try { if (signalX.SignalXServers.ContainsKey(camelCased)) { signalX.SignalXServers[camelCased] = server; signalX.SignalXServerExecutionDetails[camelCased] = new ServerHandlerDetails(requireAuthorization, isSingleWriter, groupNames); // signalX.Server.GetOrAdd(camelCased, signalX.RespondToServer); if (camelCased != unCamelCased) { signalX.SignalXServers[unCamelCased] = server; signalX.SignalXServerExecutionDetails[unCamelCased] = new ServerHandlerDetails(requireAuthorization, isSingleWriter, groupNames); // signalX.Server.GetOrAdd(unCamelCased, signalX.RespondToServer); } } else { signalX.SignalXServers.GetOrAdd(camelCased, server); signalX.SignalXServerExecutionDetails.GetOrAdd(camelCased, new ServerHandlerDetails(requireAuthorization, isSingleWriter, groupNames)); // signalX.Server.GetOrAdd(camelCased, signalX. RespondToServer); if (camelCased != unCamelCased) { signalX.SignalXServers.GetOrAdd(unCamelCased, server); signalX.SignalXServerExecutionDetails.GetOrAdd(unCamelCased, new ServerHandlerDetails(requireAuthorization, isSingleWriter, groupNames)); // signalX.Server.GetOrAdd(unCamelCased, signalX.RespondToServer); } } } catch (Exception e) { signalX.Advanced.Trace(signalX.AppCorrelationId, $"Error creating a server {name} with authorized groups {string.Join(",", groupNames ?? new List<string>())} and requires authorization : {requireAuthorization}, is set to single write : {isSingleWriter} and allows dynamic server for this instance {allowDynamicServerForThisInstance}", e); signalX.Settings.ExceptionHandler.ForEach(h => h?.Invoke($"Error while creating server {name}", e)); } }
public static void EnableClient(this SignalX signalX, string clientMethodName) { signalX.Advanced.Trace(signalX.AppCorrelationId, $"Enabling client {clientMethodName}..."); signalX.UpdateClient(signalX.AppCorrelationId, clientMethodName, false); }
/// <summary> /// Runs when client is ready before client's ready functions executes /// </summary> /// <param name="signalX"></param> /// <param name="onResponse"></param> public static void OnClientReady(this SignalX signalX, Action <SignalXRequest> onResponse) { signalX.Advanced.Trace(signalX.AppCorrelationId, "Setting up OnClientReady ..."); signalX.OnClientReady.Add(onResponse); }