예제 #1
0
        /// <summary>
        /// Event raise every heartbeat
        /// </summary>
        /// <param name="source"></param>
        /// <param name="e"></param>
        private static void Heartbeat(Object source, ElapsedEventArgs e)
        {
            IHubContext hub = GlobalHost.ConnectionManager.GetHubContext <DatabaseHub>();

            if (hub == null)
            {
                return;
            }

            Info("Running heartbeat ...");

            using (Module.Administration.DatabaseContext requester = new Module.Administration.DatabaseContext())
            {
                Debug("Ping all clients connected ...");

                foreach (ConnectionRecord connection in requester._Connection.Where(c => c.Allow && c.Status).ToList())
                {
                    try
                    {
                        Verbose($"Ping the client {connection}");
                        hub.Clients.Client(connection.ConnectionId).ping();
                    }
                    catch (System.Exception exception)
                    {
                        Exception("Unable to ping the client", exception);
                    }
                }

                Debug("Disconnect all clients without any updates since a while ...");

                foreach (ConnectionRecord connection in requester._Connection.Where(c => c.Allow && c.Status).ToList())
                {
                    if (connection.ConnectionLast < DateTime.Now.AddSeconds(-ConfigurationManager.ClientHubTimeout))
                    {
                        try
                        {
                            Info($"Disconnecting the client {connection} ...");
                            hub.Clients.Client(connection.ConnectionId).stop();
                            connection.Allow = false;
                            requester.SaveChanges();
                        }
                        catch (System.Exception exception)
                        {
                            Exception("Unable to disconnect the client", exception);
                        }
                    }
                }
            }
        }
예제 #2
0
        /// <summary>
        /// Launch the heartbeat of the application if it is enabled
        /// </summary>
        public static void StartHeartbeat()
        {
            // Start Heartbeat to disconnect client if no updated done since a while

            if (ConfigurationManager.HeartbeatDelay <= 0 || ConfigurationManager.ClientHubTimeout <= 0)
            {
                return;
            }

            Info($"Launching heartbeat every {ConfigurationManager.HeartbeatDelay} seconds and disconnect clients after {ConfigurationManager.ClientHubTimeout} seconds without response ...");

            // Disconnect all connections if no updates done since a while ...

            IHubContext hub = GlobalHost.ConnectionManager.GetHubContext <DatabaseHub>();

            using (Module.Administration.DatabaseContext requester = new Module.Administration.DatabaseContext())
                foreach (ConnectionRecord connection in requester._Connection.Where(c => c.Allow && c.Status).ToList())
                {
                    if (connection.ConnectionLast < DateTime.Now.AddSeconds(-ConfigurationManager.ClientHubTimeout))
                    {
                        try
                        {
                            Info($"Disconnecting the client {connection} ...");
                            if (hub != null)
                            {
                                hub.Clients.Client(connection.ConnectionId).stop();
                            }
                            connection.Allow = false;
                            requester.SaveChanges();
                        }
                        catch (System.Exception exception)
                        {
                            Exception("Unable to disconnect the client", exception);
                        }
                    }
                }

            // Run the heartbeat

            Debug("Starting heartbeat ...");
            Timer heartbeat = new Timer(ConfigurationManager.HeartbeatDelay * 1000);

            heartbeat.Elapsed += Heartbeat;
            heartbeat.Start();
        }
예제 #3
0
        /// <summary>
        /// The client tests if the server if up ... this call generally occurs on connection on an existing account!
        /// </summary>
        public void Ping()
        {
            try
            {
                DateTime now = DateTime.Now;

                Debug($"Ping from '{Context.ConnectionId}'");

                using (Module.Administration.DatabaseContext database = new Module.Administration.DatabaseContext())
                {
                    // receive the ping from the client

                    PingRecord existingPing = database._Ping.Find(Context.ConnectionId);
                    if (existingPing != null)
                    {
                        existingPing.Date = now;
                    }
                    else
                    {
                        database._Ping.Add(new PingRecord {
                            ConnectionId = Context.ConnectionId
                        });
                    }

                    // update the last connection time of the client

                    ConnectionRecord currentConnection = database._Connection.Find(Context.ConnectionId);
                    if (currentConnection != null)
                    {
                        currentConnection.ConnectionLast = now;
                    }

                    database.SaveChanges();
                }
            }
            catch (System.Exception ex)
            {
                Exception($"An exception occurs on pinging of the connection '{Context.ConnectionId}'", ex);
                Warn("This exception is ignored ... may be the connection was previously deleted or disconnected!");
            }
        }
예제 #4
0
        /// <summary>
        /// Check if the given user is already connected through hub
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public static bool IsAlreadyConnected(int userId)
        {
            // the user exists, check if it's already connected
            // In case of reloading page, the connection can't be disconnected as quick as expected ...

            IHubContext hub = GlobalHost.ConnectionManager.GetHubContext <DatabaseHub>();

            if (hub == null)
            {
                // no hub ... disconnect the user and go to the index page

                Common.Logger.LoggerManager.Instance.Info(MODULE, $"Cleaning up all connections for the user {userId} ...");

                using (Module.Administration.DatabaseContext database = new Module.Administration.DatabaseContext())
                {
                    ConnectionRecord currentConnection = database._Connection.FirstOrDefault(c => c.UserId == userId && c.Allow);
                    while (currentConnection != null)
                    {
                        Common.Logger.LoggerManager.Instance.Debug(MODULE, $"Connection {currentConnection} removed ...");
                        try { database._Connection.Remove(currentConnection); } catch { }
                        currentConnection = database._Connection.FirstOrDefault(c => c.UserId == userId && c.Allow);
                    }
                    database.SaveChanges();
                }

                return(false);
            }

            // DatabaseCommonContext is frequently open/close here to clean up the cache of the database (else the ping record is never updated) ...

            bool     alreadyConnected = true;
            DateTime pingDate         = DateTime.Now;
            int      count            = 0;

            while (count < ConfigurationManager.ConnectionMaxWaiting && alreadyConnected)
            {
                count++;

                ConnectionRecord currentConnection = null;

                using (Module.Administration.DatabaseContext database = new Module.Administration.DatabaseContext())
                    currentConnection = database._Connection.FirstOrDefault(c => c.UserId == userId && c.Allow);

                if (currentConnection != null && count < ConfigurationManager.ConnectionMaxWaiting)
                {
                    // Ping the client and wait 1 secondes to check if the client responses

                    if (count == 1)
                    {
                        Thread.Sleep(1000);
                        Common.Logger.LoggerManager.Instance.Debug(MODULE, $"Ping to '{currentConnection.ConnectionId}'");
                        hub.Clients.Client(currentConnection.ConnectionId).ping();
                    }

                    // Did the client answer to the ping ?

                    PingRecord currentPing = null;
                    using (Module.Administration.DatabaseContext database = new Module.Administration.DatabaseContext())
                        currentPing = database._Ping.Find(currentConnection.ConnectionId);

                    // The client has answered to the ping ... So, it already exists

                    if (currentPing != null && DateTime.Compare(currentPing.Date, pingDate) >= 0)
                    {
                        break;
                    }

                    // The client didn't answer ... wait a few more second

                    if (count > 1)
                    {
                        Thread.Sleep(1000);
                    }
                }
                else if (currentConnection != null)
                {
                    // The max seconds has expired ... it means that no client is already connected ... disconnect it

                    alreadyConnected = false;

                    try
                    {
                        hub.Clients.Client(currentConnection.ConnectionId).stop();
                        Common.Logger.LoggerManager.Instance.Info(MODULE, $"The connection '{currentConnection.ConnectionId}' is disconnected");
                    }
                    catch (System.Exception ex)
                    {
                        Common.Logger.LoggerManager.Instance.Exception(MODULE, $"(Warning) Unable to disconnect '{currentConnection.ConnectionId}' due to an exception", ex);
                    }

                    using (Module.Administration.DatabaseContext database = new Module.Administration.DatabaseContext())
                    {
                        currentConnection       = database._Connection.Find(currentConnection.ConnectionId);
                        currentConnection.Allow = false;
                        database.SaveChanges();
                    }
                }
                else
                {
                    alreadyConnected = false;
                    Common.Logger.LoggerManager.Instance.Info(MODULE, $"No connection already existing or the previous connection is disconnected ...");
                }
            }

            if (alreadyConnected)
            {
                Common.Logger.LoggerManager.Instance.Debug(MODULE, $"The user '{userId}' is already connected on another support");
                return(true);
            }

            return(false);
        }
예제 #5
0
        /// <summary>
        /// Initialize the application
        /// </summary>
        private void Initialize()
        {
            StatusManager.Status = StatusManager.EStatus.STATUS_OK;

            // Initialize Log4Net and LoggerManager

            try
            {
                log4net.Config.XmlConfigurator.Configure(new FileInfo(Server.MapPath("~/Web.config")));
                Common.Logger.LoggerManager.Instance.Initialize();
            }
            catch (System.Exception ex)
            {
                // Impossible to start the application due to an abnormal situation on initializing
                // The log manager is not currently running !
                StatusManager.Status    = StatusManager.EStatus.STATUS_FAIL;
                StatusManager.Exception = ex;
                return;
            }

            // Log settings from web.config

            try
            {
                Info("Settings into the web.config");
                foreach (KeyValuePair <string, string> setting in ConfigurationManager.Settings)
                {
                    Info($"Setting[{setting.Key}] = '{setting.Value}'");
                }
            }
            catch (System.Exception ex)
            {
                Exception("An exception occurs during reading the settings", ex);
            }

            try
            {
                string connectionString = WebConfigurationManager.ConnectionStrings[ConfigurationManager.CONNEXION_STRING]?.ConnectionString;
                if (connectionString == null)
                {
                    connectionString = "";
                }

                Debug($"Connection String to the database is '{connectionString}'");

                using (Module.Administration.DatabaseContext database = new Module.Administration.DatabaseContext())
                {
                    // Open a connection to the database

                    database.Database.Connection.Open();

                    // Does the database upgrade towards the latest version ?

                    if (database.HasToUpgrade())
                    {
                        Warn("A upgrading process must be run");
                        StatusManager.Status = StatusManager.EStatus.STATUS_UPGRADING;
                        return;
                    }

                    // Build the database schema

                    ConfigurationManager.Schemas[Module.Administration.DatabaseContext.AREA_NAME] = new Common.Database.DSSchema.DSDatabase(typeof(Module.Administration.DatabaseContext), new DatabaseRequest());
                    Info($"Database schema[{Module.Administration.DatabaseContext.AREA_NAME}] : '{ConfigurationManager.Schemas[Module.Administration.DatabaseContext.AREA_NAME]}'");

                    ConfigurationManager.Schemas[Module.Customer.DatabaseContext.AREA_NAME] = new Common.Database.DSSchema.DSDatabase(typeof(Module.Customer.DatabaseContext), new DatabaseRequest());
                    Info($"Database schema[{Module.Customer.DatabaseContext.AREA_NAME}] : '{ConfigurationManager.Schemas[Module.Customer.DatabaseContext.AREA_NAME]}'");

                    // Log settings from database

                    Info("Settings into the database");
                    foreach (ParameterRecord parameter in database._Parameter)
                    {
                        Info($"Parameter[{parameter.Key}] = '{parameter.Value}'");
                    }

                    /*  Clean up all connection from this server */

                    if (ConfigurationManager.ConnectionCleanup)
                    {
                        database.CleanupConnection();
                    }

                    /* Remove files older than max number of days from ~/App_Data */

                    if (ConfigurationManager.AppDataMaxDays < 0)
                    {
                        Info("Do not clean up the folder ~/App_Data");
                    }
                    else
                    {
                        int nbFilesDeleted = 0;
                        Info("Cleaning up the folder ~/App_Data ...");
                        foreach (String filename in Directory.GetFiles(Server.MapPath("~/App_Data")))
                        {
                            Debug($"Cleaning up the file '{filename}' ...");

                            FileAttributes fileAttr = File.GetAttributes(filename);

                            if (fileAttr.HasFlag(FileAttributes.Directory) ||
                                Path.GetFileName(filename).Equals("UploadFiles.txt"))
                            {
                                Debug($"The file '{filename}' mustn't be deleted ...");
                                continue;
                            }

                            FileInfo fileInfo = new FileInfo(filename);
                            if (fileInfo.CreationTime >= DateTime.Now.AddDays(-ConfigurationManager.AppDataMaxDays))
                            {
                                Info($"Keep the file '{filename}'");
                                continue;
                            }

                            try
                            {
                                fileInfo.Delete();
                                Info($"'{filename}' deleted");
                                nbFilesDeleted++;
                            }
                            catch (System.Exception ex)
                            {
                                Exception($"Unable to delete '{filename}'", ex);
                            }
                        }
                        Info($"{nbFilesDeleted} files deleted");
                    }

                    // Initialize the cache manager for all known customers

                    if (DatabaseCacheManager.Instance.IsEnable)
                    {
                        Debug($"Loading data into the cache manager for all customers ...");
                        List <int> customerIds = database.Customer.Select(c => c.Id).ToList();
                        DatabaseCacheManager.Instance.Initialize(database, customerIds, Syncytium.Managers.DatabaseManager.GetDatabase);
                        Info($"Data loaded into the cache manager for all customers ...");
                    }
                    else
                    {
                        Info("The database cache manager is disabled");
                    }

                    // Load all labels

                    LanguageManager.GetInstance(database);
                }
            }
            catch (System.Exception ex)
            {
                Exception("An exception occurs during initializing database connection", ex);
                StatusManager.Status    = StatusManager.EStatus.STATUS_FAIL;
                StatusManager.Exception = ex;
                return;
            }

            // Run threads

            DatabaseQueue.Instance.StartConsumer();
            StartHeartbeat();
        }
        /// <summary>
        /// Apply the filter to an action of the controller
        /// </summary>
        /// <param name="filterContext"></param>
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (IsVerbose())
            {
                Verbose($"Check if the current user is allowed to get access to the target page ({filterContext.HttpContext.Request.RawUrl}) - AllModules = {(AllModules ? "true" : "false")} - Module = {Module} - Role = {Role}");
            }

            // if the user is not authenticated ... can't access to the page ... redirect to the sign in page

            if (!HttpContext.Current.User.Identity.IsAuthenticated)
            {
                Verbose("The user has to be authenticated!");

                filterContext.Result = ((SyncytiumController)filterContext.Controller).RedirectToAction("SignIn", "User", "Administration", filterContext.HttpContext.Request.RawUrl);
                base.OnActionExecuting(filterContext);
                return;
            }

            if (Ping)
            {
                base.OnActionExecuting(filterContext);
                return;
            }


            // it is due to a upgrading process ... no error because StatusFilterAttribute has already rejected the action

            if (StatusManager.Status != StatusManager.EStatus.STATUS_OK)
            {
                Info("The server is not available!");

                if (!HttpContext.Current.User.Identity.Name.Equals("-1"))
                {
                    Warn("Only the administrator default user can get access! ");
                    FormsAuthentication.SignOut();

                    filterContext.Result = ((SyncytiumController)filterContext.Controller).RedirectToAction("SignIn", "User", "Administration", "", "ERR_UNAUTHORIZED");
                }

                Verbose("The user is allowed!");

                base.OnActionExecuting(filterContext);
                return;
            }

            // check if the user expected must be only connected (default)

            if (AllModules && Role == UserProfile.EUserProfile.None)
            {
                Verbose("The user is authenticated!");

                base.OnActionExecuting(filterContext);
                return;
            }

            // check if the user gets access on Customer or Administration screen

            if (!AllModules && Module == EModule.None)
            {
                // the default administrator user is allowed to get to this feature

                if (HttpContext.Current.User.Identity.Name.Equals("-1"))
                {
                    Warn("The default administrator is allowed!");

                    base.OnActionExecuting(filterContext);
                    return;
                }

                // the user connected must be for CustomerId = 1

                try
                {
                    using (Syncytium.Module.Administration.DatabaseContext dbContext = new Module.Administration.DatabaseContext())
                    {
                        UserManager database = new UserManager(dbContext);

                        if (!(database.GetById(int.Parse(HttpContext.Current.User.Identity.Name)) is UserRecord currentUser) || currentUser.CustomerId != 1)
                        {
                            Warn("The current user is not the user of the first customer!");

                            // The login doesn't exist, is it the administrator default login ?
                            // Or, Only the user defined for CustomerId = 1 can get access to the screen

                            FormsAuthentication.SignOut();
                            filterContext.Result = ((SyncytiumController)filterContext.Controller).RedirectToAction("SignIn", "User", "Administration", "", "ERR_UNAUTHORIZED");
                        }
                        else
                        {
                            Info("The user of the first customer is allowed!");
                        }
                    }