using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;
using SuperSocket.SocketBase;
using SuperSocket.SocketBase.Config;
using SuperSocket.SocketBase.Metadata;
using SuperSocket.SocketBase.Provider;
namespace SuperSocket.SocketEngine
{
abstract class IsolationAppServer : MarshalByRefObject, IWorkItem, IStatusInfoSource, IExceptionSource, IDisposable
{
protected const string WorkingDir = "AppRoot";
protected string ServerTypeName { get; private set; }
protected IBootstrap Bootstrap { get; private set; }
public IServerConfig Config { get; private set; }
protected ProviderFactoryInfo[] Factories { get; private set; }
protected IWorkItemBase AppServer { get; private set; }
public string Name { get; private set; }
private StatusInfoAttribute[] m_ServerStatusMetadata;
private AutoResetEvent m_StopResetEvent = new AutoResetEvent(false);
protected IsolationAppServer(string serverTypeName, StatusInfoAttribute[] serverStatusMetadata)
{
State = ServerState.NotInitialized;
ServerTypeName = serverTypeName;
m_ServerStatusMetadata = PrepareStatusMetadata(serverStatusMetadata);
}
///
/// Gets a value indicating whether [status metadata extended].
///
///
/// true if [status metadata extended]; otherwise, false.
///
protected virtual bool StatusMetadataExtended
{
get { return false; }
}
private StatusInfoAttribute[] PrepareStatusMetadata(StatusInfoAttribute[] serverStatusMetadata)
{
if (!StatusMetadataExtended)
return serverStatusMetadata;
var additionalAttrs = this.GetType()
.GetCustomAttributes(typeof(StatusInfoAttribute), true)
.OfType()
.ToArray();
if (additionalAttrs.Length == 0)
return serverStatusMetadata;
var list = serverStatusMetadata.ToList();
list.AddRange(additionalAttrs);
return list.ToArray();
}
protected AppDomain CreateHostAppDomain()
{
var currentDomain = AppDomain.CurrentDomain;
var workingDir = Path.Combine(Path.Combine(currentDomain.BaseDirectory, WorkingDir), Name);
if (!Directory.Exists(workingDir))
Directory.CreateDirectory(workingDir);
var startupConfigFile = Bootstrap.StartupConfigFile;
if (!string.IsNullOrEmpty(startupConfigFile))
{
if (!Path.IsPathRooted(startupConfigFile))
startupConfigFile = Path.Combine(currentDomain.BaseDirectory, startupConfigFile);
}
var hostAppDomain = AppDomain.CreateDomain(Name, currentDomain.Evidence, new AppDomainSetup
{
ApplicationName = Name,
ApplicationBase = workingDir,
ConfigurationFile = startupConfigFile
});
var assemblyImportType = typeof(AssemblyImport);
hostAppDomain.CreateInstanceFrom(assemblyImportType.Assembly.CodeBase,
assemblyImportType.FullName,
true,
BindingFlags.CreateInstance,
null,
new object[] { currentDomain.BaseDirectory },
null,
new object[0]);
return hostAppDomain;
}
public virtual bool Setup(IBootstrap bootstrap, IServerConfig config, ProviderFactoryInfo[] factories)
{
State = ServerState.Initializing;
Name = config.Name;
Bootstrap = bootstrap;
Config = config;
Factories = factories;
State = ServerState.NotStarted;
return true;
}
public virtual void ReportPotentialConfigChange(IServerConfig config)
{
Config = config;
if (State != ServerState.Stopping && State != ServerState.NotStarted)
return;
var appServer = AppServer;
if (appServer == null)
return;
appServer.ReportPotentialConfigChange(config);
}
protected abstract IWorkItemBase Start();
bool IWorkItemBase.Start()
{
State = ServerState.Starting;
AppServer = Start();
if (AppServer != null)
{
State = ServerState.Running;
return true;
}
else
{
State = ServerState.NotStarted;
return false;
}
}
public ServerState State { get; private set; }
protected abstract void Stop();
void IWorkItemBase.Stop()
{
var appServer = AppServer;
if (appServer == null)
return;
State = ServerState.Stopping;
appServer.Stop();
Stop();
m_StopResetEvent.WaitOne();
}
protected virtual void OnStopped()
{
State = ServerState.NotStarted;
AppServer = null;
m_StopResetEvent.Set();
}
public int SessionCount
{
get
{
var appServer = AppServer;
if (appServer == null)
return 0;
return appServer.SessionCount;
}
}
public StatusInfoAttribute[] GetServerStatusMetadata()
{
return m_ServerStatusMetadata;
}
private StatusInfoCollection m_PrevStatus;
private StatusInfoCollection m_StoppedStatus;
private StatusInfoCollection GetStoppedStatus()
{
if (m_StoppedStatus == null)
{
m_StoppedStatus = new StatusInfoCollection();
m_StoppedStatus.Name = Name;
m_StoppedStatus.Tag = Name;
m_StoppedStatus[StatusInfoKeys.IsRunning] = false;
m_StoppedStatus[StatusInfoKeys.MaxConnectionNumber] = Config.MaxConnectionNumber;
if (m_PrevStatus != null)
{
m_StoppedStatus[StatusInfoKeys.Listeners] = m_PrevStatus[StatusInfoKeys.Listeners];
}
}
return m_StoppedStatus;
}
public virtual StatusInfoCollection CollectServerStatus(StatusInfoCollection nodeStatus)
{
var appServer = AppServer;
if (appServer == null)
{
var stoppedStatus = GetStoppedStatus();
stoppedStatus.CollectedTime = DateTime.Now;
return stoppedStatus;
}
var currentStatus = appServer.CollectServerStatus(nodeStatus);
m_PrevStatus = currentStatus;
return currentStatus;
}
///
/// Obtains a lifetime service object to control the lifetime policy for this instance.
/// Return null, never expired
///
///
/// An object of type used to control the lifetime policy for this instance. This is the current lifetime service object for this instance if one exists; otherwise, a new lifetime service object initialized to the value of the property.
///
///
///
///
public override object InitializeLifetimeService()
{
return null;
}
public void Dispose()
{
Dispose(true);
// Use SupressFinalize in case a subclass
// of this type implements a finalizer.
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
Stop();
}
~IsolationAppServer()
{
Dispose(false);
}
public event EventHandler ExceptionThrown;
protected void OnExceptionThrown(Exception exc)
{
var handler = ExceptionThrown;
if (handler == null)
return;
handler(this, new SuperSocket.Common.ErrorEventArgs(exc));
}
public void TransferSystemMessage(string messageType, object messageData)
{
var appServer = AppServer;
if (appServer == null)
OnExceptionThrown(new Exception("You cannot send system message to the instance who is not started."));
appServer.TransferSystemMessage(messageType, messageData);
}
}
}