using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using SuperSocket.Common;
using SuperSocket.SocketBase.Command;
using SuperSocket.SocketBase.Config;
using SuperSocket.SocketBase.Protocol;
using SuperSocket.SocketBase.Security;
namespace SuperSocket.SocketBase
{
///
/// AppServer class
///
public class AppServer : AppServer
{
///
/// Initializes a new instance of the class.
///
public AppServer()
: base()
{
}
///
/// Initializes a new instance of the class.
///
/// The Receive filter factory.
public AppServer(IReceiveFilterFactory receiveFilterFactory)
: base(receiveFilterFactory)
{
}
}
///
/// AppServer class
///
/// The type of the app session.
public class AppServer : AppServer
where TAppSession : AppSession, IAppSession, new()
{
///
/// Initializes a new instance of the class.
///
public AppServer()
: base()
{
}
///
/// Initializes a new instance of the class.
///
/// The Receive filter factory.
public AppServer(IReceiveFilterFactory receiveFilterFactory)
: base(receiveFilterFactory)
{
}
internal override IReceiveFilterFactory CreateDefaultReceiveFilterFactory()
{
return new CommandLineReceiveFilterFactory(TextEncoding);
}
}
///
/// AppServer basic class
///
/// The type of the app session.
/// The type of the request info.
public abstract class AppServer : AppServerBase
where TRequestInfo : class, IRequestInfo
where TAppSession : AppSession, IAppSession, new()
{
///
/// Initializes a new instance of the class.
///
public AppServer()
: base()
{
}
///
/// Initializes a new instance of the class.
///
/// The protocol.
protected AppServer(IReceiveFilterFactory protocol)
: base(protocol)
{
}
internal override IReceiveFilterFactory CreateDefaultReceiveFilterFactory()
{
return null;
}
///
/// Starts this AppServer instance.
///
///
public override bool Start()
{
if (!base.Start())
return false;
if (!Config.DisableSessionSnapshot)
StartSessionSnapshotTimer();
if (Config.ClearIdleSession)
StartClearSessionTimer();
return true;
}
private ConcurrentDictionary m_SessionDict = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase);
///
/// Registers the session into the session container.
///
/// The session ID.
/// The app session.
///
protected override bool RegisterSession(string sessionID, TAppSession appSession)
{
if (m_SessionDict.TryAdd(sessionID, appSession))
return true;
if (Logger.IsErrorEnabled)
Logger.Error(appSession, "The session is refused because the it's ID already exists!");
return false;
}
///
/// Gets the app session by ID.
///
/// The session ID.
///
[Obsolete("Use the method GetSessionByID instead")]
public TAppSession GetAppSessionByID(string sessionID)
{
return GetSessionByID(sessionID);
}
///
/// Gets the app session by ID.
///
/// The session ID.
///
public override TAppSession GetSessionByID(string sessionID)
{
if (string.IsNullOrEmpty(sessionID))
return NullAppSession;
TAppSession targetSession;
m_SessionDict.TryGetValue(sessionID, out targetSession);
return targetSession;
}
///
/// Called when [socket session closed].
///
/// The session.
/// The reason.
protected override void OnSessionClosed(TAppSession session, CloseReason reason)
{
string sessionID = session.SessionID;
if (!string.IsNullOrEmpty(sessionID))
{
TAppSession removedSession;
if (!m_SessionDict.TryRemove(sessionID, out removedSession))
{
if (Logger.IsErrorEnabled)
Logger.Error(session, "Failed to remove this session, Because it has't been in session container!");
}
}
base.OnSessionClosed(session, reason);
}
///
/// Gets the total session count.
///
public override int SessionCount
{
get
{
return m_SessionDict.Count;
}
}
#region Clear idle sessions
private System.Threading.Timer m_ClearIdleSessionTimer = null;
private void StartClearSessionTimer()
{
int interval = Config.ClearIdleSessionInterval * 1000;//in milliseconds
m_ClearIdleSessionTimer = new System.Threading.Timer(ClearIdleSession, new object(), interval, interval);
}
///
/// Clears the idle session.
///
/// The state.
private void ClearIdleSession(object state)
{
if (Monitor.TryEnter(state))
{
try
{
var sessionSource = SessionSource;
if (sessionSource == null)
return;
DateTime now = DateTime.Now;
DateTime timeOut = now.AddSeconds(0 - Config.IdleSessionTimeOut);
var timeOutSessions = sessionSource.Where(s => s.Value.LastActiveTime <= timeOut).Select(s => s.Value);
System.Threading.Tasks.Parallel.ForEach(timeOutSessions, s =>
{
if (Logger.IsInfoEnabled)
Logger.Info(s, string.Format("The session will be closed for {0} timeout, the session start time: {1}, last active time: {2}!", now.Subtract(s.LastActiveTime).TotalSeconds, s.StartTime, s.LastActiveTime));
s.Close(CloseReason.TimeOut);
});
}
catch (Exception e)
{
if(Logger.IsErrorEnabled)
Logger.Error("Clear idle session error!", e);
}
finally
{
Monitor.Exit(state);
}
}
}
private KeyValuePair[] SessionSource
{
get
{
if (Config.DisableSessionSnapshot)
return m_SessionDict.ToArray();
else
return m_SessionsSnapshot;
}
}
#endregion
#region Take session snapshot
private System.Threading.Timer m_SessionSnapshotTimer = null;
private KeyValuePair[] m_SessionsSnapshot = new KeyValuePair[0];
private void StartSessionSnapshotTimer()
{
int interval = Math.Max(Config.SessionSnapshotInterval, 1) * 1000;//in milliseconds
m_SessionSnapshotTimer = new System.Threading.Timer(TakeSessionSnapshot, new object(), interval, interval);
}
private void TakeSessionSnapshot(object state)
{
if (Monitor.TryEnter(state))
{
Interlocked.Exchange(ref m_SessionsSnapshot, m_SessionDict.ToArray());
Monitor.Exit(state);
}
}
#endregion
#region Search session utils
///
/// Gets the matched sessions from sessions snapshot.
///
/// The prediction critera.
///
public override IEnumerable GetSessions(Func critera)
{
var sessionSource = SessionSource;
if (sessionSource == null)
return null;
return sessionSource.Select(p => p.Value).Where(critera);
}
///
/// Gets all sessions in sessions snapshot.
///
///
public override IEnumerable GetAllSessions()
{
var sessionSource = SessionSource;
if (sessionSource == null)
return null;
return sessionSource.Select(p => p.Value);
}
///
/// Stops this instance.
///
public override void Stop()
{
base.Stop();
if (m_SessionSnapshotTimer != null)
{
m_SessionSnapshotTimer.Change(Timeout.Infinite, Timeout.Infinite);
m_SessionSnapshotTimer.Dispose();
m_SessionSnapshotTimer = null;
}
if (m_ClearIdleSessionTimer != null)
{
m_ClearIdleSessionTimer.Change(Timeout.Infinite, Timeout.Infinite);
m_ClearIdleSessionTimer.Dispose();
m_ClearIdleSessionTimer = null;
}
m_SessionsSnapshot = null;
var sessions = m_SessionDict.ToArray();
if (sessions.Length > 0)
{
var tasks = new Task[sessions.Length];
for (var i = 0; i < tasks.Length; i++)
{
tasks[i] = Task.Factory.StartNew((s) =>
{
var session = s as TAppSession;
if (session != null)
{
session.Close(CloseReason.ServerShutdown);
}
}, sessions[i].Value);
}
Task.WaitAll(tasks);
}
}
#endregion
}
}