From 41bc1324715ac7fe7770602b4a271bcfa81bb68e Mon Sep 17 00:00:00 2001 From: Adam Driscoll Date: Mon, 30 Sep 2019 16:36:34 -0600 Subject: [PATCH] Fix issue with sessions. --- .../Controllers/ComponentController.cs | 23 ++--- .../Execution/EndpointProvider.cs | 88 ++++++++++++------- .../Interfaces/IEndpointService.cs | 6 +- src/UniversalDashboard/Models/SessionState.cs | 7 +- src/UniversalDashboard/Server/DashboardHub.cs | 9 +- .../Server/ServerStartup.cs | 13 ++- .../UniversalDashboard.csproj | 1 - src/client/src/app/services/fetch-service.jsx | 20 +++-- .../services/universal-dashboard-service.jsx | 1 + src/client/src/app/ud-dashboard.jsx | 9 +- 10 files changed, 104 insertions(+), 73 deletions(-) diff --git a/src/UniversalDashboard/Controllers/ComponentController.cs b/src/UniversalDashboard/Controllers/ComponentController.cs index 856573a7..fa944973 100644 --- a/src/UniversalDashboard/Controllers/ComponentController.cs +++ b/src/UniversalDashboard/Controllers/ComponentController.cs @@ -21,7 +21,7 @@ using UniversalDashboard.Interfaces; using UniversalDashboard.Models.Basics; using System.Security; -using StackExchange.Profiling; +using Microsoft.Extensions.Primitives; namespace UniversalDashboard.Controllers { @@ -29,7 +29,6 @@ namespace UniversalDashboard.Controllers public class ComponentController : Controller { private static readonly Logger Log = LogManager.GetLogger(nameof(ComponentController)); - private readonly IExecutionService _executionService; private readonly IDashboardService _dashboardService; private readonly AutoReloader _autoReloader; @@ -74,23 +73,19 @@ private async Task RunScript(Endpoint endpoint, Dictionary { - return await Task.Run(() => - { - var result = _executionService.ExecuteEndpoint(executionContext, endpoint); - var actionResult = ConvertToActionResult(result); + var result = _executionService.ExecuteEndpoint(executionContext, endpoint); + var actionResult = ConvertToActionResult(result); - return actionResult; - }); - } + return actionResult; + }); } catch (Exception ex) { Log.Warn("RunScript() " + ex.Message + Environment.NewLine + ex.StackTrace); diff --git a/src/UniversalDashboard/Execution/EndpointProvider.cs b/src/UniversalDashboard/Execution/EndpointProvider.cs index a1bf94cc..3399e2e4 100644 --- a/src/UniversalDashboard/Execution/EndpointProvider.cs +++ b/src/UniversalDashboard/Execution/EndpointProvider.cs @@ -11,7 +11,6 @@ namespace UniversalDashboard.Execution { public class EndpointService : IEndpointService { - private readonly MemoryCache _endpointCache; private readonly List _restEndpoints; private readonly List _scheduledEndpoints; private static readonly Logger logger = LogManager.GetLogger("EndpointService"); @@ -22,6 +21,9 @@ public class EndpointService : IEndpointService private static IEndpointService _instance; + public Dictionary Endpoints { get; private set; } + public Dictionary Sessions { get; private set; } + public static IEndpointService Instance { get @@ -37,29 +39,54 @@ public static IEndpointService Instance private EndpointService() { - _endpointCache = new MemoryCache(new MemoryCacheOptions()); + Endpoints = new Dictionary(); + Sessions = new Dictionary(); + _restEndpoints = new List(); _scheduledEndpoints = new List(); } - public MemoryCache EndpointCache => _endpointCache; - - public void StartSession(string sessionId) + public void StartSession(string sessionId, string connectionId) { lock(sessionLock) { - if (_sessionLocks.ContainsKey(sessionId)) return; - _endpointCache.Set(Constants.SessionState + sessionId, new SessionState()); - _sessionLocks.Add(sessionId, new object()); + if (_sessionLocks.ContainsKey(sessionId)) + { + lock(_sessionLocks[sessionId]) + { + var session = Sessions[sessionId]; + session.ConnectionIds.Add(connectionId); + } + } + else + { + Sessions.Add(sessionId, new SessionState { + ConnectionIds = new List { + connectionId + } + }); + _sessionLocks.Add(sessionId, new object()); + } } } - public void EndSession(string sessionId) + public void EndSession(string sessionId, string connectionId) { lock(sessionLock) { - _endpointCache.Remove(Constants.SessionState + sessionId); - _sessionLocks.Remove(sessionId); + var session = Sessions[sessionId]; + if (session.ConnectionIds.Count <= 1) + { + Sessions.Remove(sessionId); + _sessionLocks.Remove(sessionId); + } + else + { + lock(_sessionLocks[sessionId]) + { + session.ConnectionIds.Remove(connectionId); + } + } } } @@ -82,7 +109,7 @@ public void Register(Endpoint callback) if (callback.SessionId == null) { - _endpointCache.Set(callback.Name, callback); + Endpoints.Add(callback.Name, callback); } else { @@ -90,16 +117,16 @@ public void Register(Endpoint callback) { if (!_sessionLocks.ContainsKey(callback.SessionId)) { - StartSession(callback.SessionId); + StartSession(callback.SessionId, string.Empty); } } lock(_sessionLocks[callback.SessionId]) { - if (_endpointCache.TryGetValue(Constants.SessionState + callback.SessionId, out SessionState sessionState)) + if (Sessions.ContainsKey(callback.SessionId)) { - sessionState.Endpoints.Add(callback); - _endpointCache.Set(Constants.SessionState + callback.SessionId, sessionState); + var session = Sessions[callback.SessionId]; + session.Endpoints.Add(callback.Name, callback); } } } @@ -130,24 +157,23 @@ public void Unregister(string name, string sessionId) if (sessionId == null) { - if (_endpointCache.TryGetValue(name, out object result)) + if (Endpoints.ContainsKey(name)) { + Endpoints.Remove(name); logger.Debug("Endpoint found. Removing endpoint."); - _endpointCache.Remove(name); } } else { - if (_endpointCache.TryGetValue(Constants.SessionState + sessionId, out SessionState sessionState)) + if (Sessions.ContainsKey(sessionId)) { - var endpoint = sessionState.Endpoints.FirstOrDefault(m => m.Name?.Equals(name, StringComparison.OrdinalIgnoreCase) == true); - if (endpoint != null) + var session = Sessions[sessionId]; + if (session.Endpoints.ContainsKey(name)) { logger.Debug("Session endpoint found. Removing endpoint."); - lock(sessionState.SyncRoot) + lock(session.SyncRoot) { - sessionState.Endpoints.Remove(endpoint); - _endpointCache.Set(Constants.SessionState + sessionId, sessionState); + session.Endpoints.Remove(name); } } } @@ -157,25 +183,23 @@ public void Unregister(string name, string sessionId) public Endpoint Get(string name, string sessionId) { logger.Debug($"Get() {name} {sessionId}"); - - Endpoint callback; if (sessionId != null) { - if (_endpointCache.TryGetValue(Constants.SessionState + sessionId, out SessionState sessionState)) + if (Sessions.ContainsKey(sessionId)) { - var endpoint = sessionState.Endpoints.FirstOrDefault(m => m.Name?.Equals(name, StringComparison.OrdinalIgnoreCase) == true); - if (endpoint != null) + var session = Sessions[sessionId]; + if (session.Endpoints.ContainsKey(name)) { logger.Debug("Found session endpoint."); - return endpoint; + return session.Endpoints[name]; } } } - if (_endpointCache.TryGetValue(name, out callback)) + if (Endpoints.ContainsKey(name)) { logger.Debug("Found endpoint."); - return callback; + return Endpoints[name]; } return null; diff --git a/src/UniversalDashboard/Interfaces/IEndpointService.cs b/src/UniversalDashboard/Interfaces/IEndpointService.cs index 884eae39..764f3f14 100644 --- a/src/UniversalDashboard/Interfaces/IEndpointService.cs +++ b/src/UniversalDashboard/Interfaces/IEndpointService.cs @@ -10,7 +10,9 @@ public interface IEndpointService Endpoint GetByUrl(string url, string method, Dictionary matchedVariables); IEnumerable GetScheduledEndpoints(); void Register(Endpoint callback); - void StartSession(string sessionId); - void EndSession(string sessionId); + void StartSession(string sessionId, string connectionId); + void EndSession(string sessionId, string connectionId); + Dictionary Endpoints { get; } + Dictionary Sessions { get; } } } diff --git a/src/UniversalDashboard/Models/SessionState.cs b/src/UniversalDashboard/Models/SessionState.cs index 7bb80b57..eb3b77d2 100644 --- a/src/UniversalDashboard/Models/SessionState.cs +++ b/src/UniversalDashboard/Models/SessionState.cs @@ -6,12 +6,13 @@ public class SessionState { public SessionState() { - Endpoints = new List(); + Endpoints = new Dictionary(); + ConnectionIds = new List(); SyncRoot = new object(); } public object SyncRoot { get; set; } - - public List Endpoints { get; set; } + public List ConnectionIds { get; set; } + public Dictionary Endpoints { get; set; } } } diff --git a/src/UniversalDashboard/Server/DashboardHub.cs b/src/UniversalDashboard/Server/DashboardHub.cs index 3a3807ab..1f63da40 100644 --- a/src/UniversalDashboard/Server/DashboardHub.cs +++ b/src/UniversalDashboard/Server/DashboardHub.cs @@ -144,7 +144,7 @@ public override async Task OnDisconnectedAsync(Exception exception) if (sessionId != null) { _memoryCache.Remove(sessionId); - _dashboardService.EndpointService.EndSession(sessionId as string); + _dashboardService.EndpointService.EndSession(sessionId as string, Context.ConnectionId); } _memoryCache.Remove(Context.ConnectionId); @@ -154,11 +154,10 @@ public async Task SetSessionId(string sessionId) { Log.Debug($"SetSessionId({sessionId})"); - await Task.FromResult(0); - _memoryCache.Set(Context.ConnectionId, sessionId); - _memoryCache.Set(sessionId, Context.ConnectionId); - _dashboardService.EndpointService.StartSession(sessionId); + _dashboardService.EndpointService.StartSession(sessionId, Context.ConnectionId); + + await Clients.All.SendAsync("setConnectionId", Context.ConnectionId); } public Task Reload() diff --git a/src/UniversalDashboard/Server/ServerStartup.cs b/src/UniversalDashboard/Server/ServerStartup.cs index e58044e6..227dc53e 100644 --- a/src/UniversalDashboard/Server/ServerStartup.cs +++ b/src/UniversalDashboard/Server/ServerStartup.cs @@ -68,8 +68,6 @@ public void ConfigureServices(IServiceCollection services) options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; }); - services.AddMiniProfiler(); - var serviceDescriptor = services.FirstOrDefault(descriptor => descriptor.ServiceType.Name == "IRegistryPolicyResolver"); services.Remove(serviceDescriptor); } @@ -123,11 +121,11 @@ public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHos ContentTypeProvider = provider }); - var dashboardService = app.ApplicationServices.GetService(typeof(IDashboardService)) as IDashboardService; + var dashboardService = app.ApplicationServices.GetService(typeof(IDashboardService)) as IDashboardService; - if (dashboardService?.DashboardOptions?.Certificate != null || dashboardService?.DashboardOptions?.CertificateFile != null) { - app.UseHttpsRedirection(); - } + if (dashboardService?.DashboardOptions?.Certificate != null || dashboardService?.DashboardOptions?.CertificateFile != null) { + app.UseHttpsRedirection(); + } if (dashboardService?.DashboardOptions?.PublishedFolders != null) { foreach(var publishedFolder in dashboardService.DashboardOptions.PublishedFolders) { @@ -147,12 +145,11 @@ public void Configure(IApplicationBuilder app, Microsoft.AspNetCore.Hosting.IHos { routes.MapHub("/dashboardhub"); }); + app.UseWebSockets(); app.UseSession(); - app.UseMiniProfiler(); - app.UseMvc(); } } diff --git a/src/UniversalDashboard/UniversalDashboard.csproj b/src/UniversalDashboard/UniversalDashboard.csproj index a3b024f1..61aff7da 100644 --- a/src/UniversalDashboard/UniversalDashboard.csproj +++ b/src/UniversalDashboard/UniversalDashboard.csproj @@ -28,7 +28,6 @@ - diff --git a/src/client/src/app/services/fetch-service.jsx b/src/client/src/app/services/fetch-service.jsx index d37ed4bf..2253a88c 100644 --- a/src/client/src/app/services/fetch-service.jsx +++ b/src/client/src/app/services/fetch-service.jsx @@ -2,7 +2,10 @@ import {getApiPath} from 'config' export const fetchGet = function(url, success, history) { fetch(getApiPath() + url, { - credentials: 'include' + credentials: 'include', + headers: { + 'UDConnectionId': UniversalDashboard.connectionId + } }) .then(function(response){ UniversalDashboard.invokeMiddleware('GET', url, history, response); @@ -36,7 +39,8 @@ export const fetchPost = function(url, data, success) { method: 'post', headers: { 'Accept': 'application/json, text/plain, */*', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'UDConnectionId': UniversalDashboard.connectionId }, body: JSON.stringify(data), credentials: 'include' @@ -62,7 +66,8 @@ export const fetchPostFormData = function(url, data, success) { fetch(getApiPath() + url, { method: 'post', headers: { - 'Accept': 'application/json, text/plain, */*'//, + 'Accept': 'application/json, text/plain, */*', + 'UDConnectionId': UniversalDashboard.connectionId //'Content-Type': 'multipart/form-data' }, body: data, @@ -90,7 +95,8 @@ export const fetchDelete = function(url, data, success) { method: 'delete', headers: { 'Accept': 'application/json, text/plain, */*', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'UDConnectionId': UniversalDashboard.connectionId }, body: JSON.stringify(data), credentials: 'include' @@ -117,7 +123,8 @@ export const fetchPut = function(url, data, success) { method: 'put', headers: { 'Accept': 'application/json, text/plain, */*', - 'Content-Type': 'application/json' + 'Content-Type': 'application/json', + 'UDConnectionId': UniversalDashboard.connectionId }, body: JSON.stringify(data), credentials: 'include' @@ -145,7 +152,8 @@ export const fetchPostRaw = function(url, data, success) { method: 'post', headers: { 'Accept': 'application/json, text/plain, */*', - 'Content-Type': 'text/plain' + 'Content-Type': 'text/plain', + 'UDConnectionId': UniversalDashboard.connectionId }, body: data, credentials: 'include' diff --git a/src/client/src/app/services/universal-dashboard-service.jsx b/src/client/src/app/services/universal-dashboard-service.jsx index fb6e7ef8..a43288b3 100644 --- a/src/client/src/app/services/universal-dashboard-service.jsx +++ b/src/client/src/app/services/universal-dashboard-service.jsx @@ -29,6 +29,7 @@ export const UniversalDashboardService = { unsubscribe: PubSub.unsubscribe, publish: PubSub.publishSync, toaster: toaster, + connectionId: '', renderComponent: function(component, history, dynamicallyLoaded) { if (component == null) return ; diff --git a/src/client/src/app/ud-dashboard.jsx b/src/client/src/app/ud-dashboard.jsx index 1c66fc79..d9515bb8 100644 --- a/src/client/src/app/ud-dashboard.jsx +++ b/src/client/src/app/ud-dashboard.jsx @@ -127,10 +127,16 @@ export default class UdDashboard extends React.Component { }); connection.on('write', (message) => { - console.log(message); PubSub.publish("write", message); }); + connection.on('setConnectionId', (id) => { + UniversalDashboard.connectionId = id; + this.setState({ + loading: false + }) + }); + PubSub.subscribe('element-event', function(e, data) { if (data.type === "requestStateResponse") { connection.invoke("requestStateResponse", data.requestId, data.state) @@ -221,7 +227,6 @@ export default class UdDashboard extends React.Component { this.setState({ dashboard: dashboard, - loading: false, sessionId: json.sessionId, authenticated: json.authenticated, design: dashboard.design,