Exemple #1
0
    void ReadAndProcessPong()
    {
        int      bytesRead        = 0;
        EndPoint responseEndpoint = AnyAddressEndpoint;

        try
        {
            bytesRead = MainSocket.ReceiveFrom(Buffer, ref responseEndpoint);
        }
        catch (SocketException e)
        {
            if (e.ErrorCode == (int)SocketError.ConnectionReset)
            {
                LogWarning("ConnectionReset");
            }
            else
            {
                LogWarning("Exception while reading from socket: " + e.ToString());
            }

            return;
        }

        string pongIdentifier = System.Text.Encoding.ASCII.GetString(Buffer, 0, bytesRead);

        if (PingRecords.ContainsKey(pongIdentifier))
        {
            PingRecord rec = PingRecords[pongIdentifier];
            rec.Stopwatch.Stop();

            PingRecords.Remove(pongIdentifier);

            int pingTime = (int)rec.Stopwatch.ElapsedMilliseconds;

            // statistics
            if (pingTime < MinPingTime)
            {
                MinPingTime = pingTime;
            }
            if (pingTime > MaxPingTime)
            {
                MaxPingTime = pingTime;
            }
            PingTimeSum += pingTime;
            PongRcvCount++;

            Log("Received pong from " + responseEndpoint + " in " + pingTime + " ms");
        }
        else
        {
            // probably outdated pong or other rabbish
        }
    }
        private async Task WriteToDatabase(string url, bool success, string errorMessage = null)
        {
            var dbContext = new DbContextFactory().CreateDbContext();
            var record    = new PingRecord
            {
                DateTime    = DateTime.UtcNow,
                IsOk        = success,
                Url         = url,
                Description = errorMessage
            };
            await dbContext.PingRecords.AddAsync(record);

            await dbContext.SaveChangesAsync();
        }
        /// <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!");
            }
        }
        /// <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);
        }