IsolationAppServer.cs 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Text;
  7. using System.Threading;
  8. using SuperSocket.SocketBase;
  9. using SuperSocket.SocketBase.Config;
  10. using SuperSocket.SocketBase.Metadata;
  11. using SuperSocket.SocketBase.Provider;
  12. namespace SuperSocket.SocketEngine
  13. {
  14. abstract class IsolationAppServer : MarshalByRefObject, IWorkItem, IStatusInfoSource, IExceptionSource, IDisposable
  15. {
  16. protected const string WorkingDir = "AppRoot";
  17. protected string ServerTypeName { get; private set; }
  18. protected IBootstrap Bootstrap { get; private set; }
  19. public IServerConfig Config { get; private set; }
  20. protected ProviderFactoryInfo[] Factories { get; private set; }
  21. protected IWorkItemBase AppServer { get; private set; }
  22. public string Name { get; private set; }
  23. private StatusInfoAttribute[] m_ServerStatusMetadata;
  24. private AutoResetEvent m_StopResetEvent = new AutoResetEvent(false);
  25. protected IsolationAppServer(string serverTypeName, StatusInfoAttribute[] serverStatusMetadata)
  26. {
  27. State = ServerState.NotInitialized;
  28. ServerTypeName = serverTypeName;
  29. m_ServerStatusMetadata = PrepareStatusMetadata(serverStatusMetadata);
  30. }
  31. /// <summary>
  32. /// Gets a value indicating whether [status metadata extended].
  33. /// </summary>
  34. /// <value>
  35. /// <c>true</c> if [status metadata extended]; otherwise, <c>false</c>.
  36. /// </value>
  37. protected virtual bool StatusMetadataExtended
  38. {
  39. get { return false; }
  40. }
  41. private StatusInfoAttribute[] PrepareStatusMetadata(StatusInfoAttribute[] serverStatusMetadata)
  42. {
  43. if (!StatusMetadataExtended)
  44. return serverStatusMetadata;
  45. var additionalAttrs = this.GetType()
  46. .GetCustomAttributes(typeof(StatusInfoAttribute), true)
  47. .OfType<StatusInfoAttribute>()
  48. .ToArray();
  49. if (additionalAttrs.Length == 0)
  50. return serverStatusMetadata;
  51. var list = serverStatusMetadata.ToList();
  52. list.AddRange(additionalAttrs);
  53. return list.ToArray();
  54. }
  55. protected AppDomain CreateHostAppDomain()
  56. {
  57. var currentDomain = AppDomain.CurrentDomain;
  58. var workingDir = Path.Combine(Path.Combine(currentDomain.BaseDirectory, WorkingDir), Name);
  59. if (!Directory.Exists(workingDir))
  60. Directory.CreateDirectory(workingDir);
  61. var startupConfigFile = Bootstrap.StartupConfigFile;
  62. if (!string.IsNullOrEmpty(startupConfigFile))
  63. {
  64. if (!Path.IsPathRooted(startupConfigFile))
  65. startupConfigFile = Path.Combine(currentDomain.BaseDirectory, startupConfigFile);
  66. }
  67. var hostAppDomain = AppDomain.CreateDomain(Name, currentDomain.Evidence, new AppDomainSetup
  68. {
  69. ApplicationName = Name,
  70. ApplicationBase = workingDir,
  71. ConfigurationFile = startupConfigFile
  72. });
  73. var assemblyImportType = typeof(AssemblyImport);
  74. hostAppDomain.CreateInstanceFrom(assemblyImportType.Assembly.CodeBase,
  75. assemblyImportType.FullName,
  76. true,
  77. BindingFlags.CreateInstance,
  78. null,
  79. new object[] { currentDomain.BaseDirectory },
  80. null,
  81. new object[0]);
  82. return hostAppDomain;
  83. }
  84. public virtual bool Setup(IBootstrap bootstrap, IServerConfig config, ProviderFactoryInfo[] factories)
  85. {
  86. State = ServerState.Initializing;
  87. Name = config.Name;
  88. Bootstrap = bootstrap;
  89. Config = config;
  90. Factories = factories;
  91. State = ServerState.NotStarted;
  92. return true;
  93. }
  94. public virtual void ReportPotentialConfigChange(IServerConfig config)
  95. {
  96. Config = config;
  97. if (State != ServerState.Stopping && State != ServerState.NotStarted)
  98. return;
  99. var appServer = AppServer;
  100. if (appServer == null)
  101. return;
  102. appServer.ReportPotentialConfigChange(config);
  103. }
  104. protected abstract IWorkItemBase Start();
  105. bool IWorkItemBase.Start()
  106. {
  107. State = ServerState.Starting;
  108. AppServer = Start();
  109. if (AppServer != null)
  110. {
  111. State = ServerState.Running;
  112. return true;
  113. }
  114. else
  115. {
  116. State = ServerState.NotStarted;
  117. return false;
  118. }
  119. }
  120. public ServerState State { get; private set; }
  121. protected abstract void Stop();
  122. void IWorkItemBase.Stop()
  123. {
  124. var appServer = AppServer;
  125. if (appServer == null)
  126. return;
  127. State = ServerState.Stopping;
  128. appServer.Stop();
  129. Stop();
  130. m_StopResetEvent.WaitOne();
  131. }
  132. protected virtual void OnStopped()
  133. {
  134. State = ServerState.NotStarted;
  135. AppServer = null;
  136. m_StopResetEvent.Set();
  137. }
  138. public int SessionCount
  139. {
  140. get
  141. {
  142. var appServer = AppServer;
  143. if (appServer == null)
  144. return 0;
  145. return appServer.SessionCount;
  146. }
  147. }
  148. public StatusInfoAttribute[] GetServerStatusMetadata()
  149. {
  150. return m_ServerStatusMetadata;
  151. }
  152. private StatusInfoCollection m_PrevStatus;
  153. private StatusInfoCollection m_StoppedStatus;
  154. private StatusInfoCollection GetStoppedStatus()
  155. {
  156. if (m_StoppedStatus == null)
  157. {
  158. m_StoppedStatus = new StatusInfoCollection();
  159. m_StoppedStatus.Name = Name;
  160. m_StoppedStatus.Tag = Name;
  161. m_StoppedStatus[StatusInfoKeys.IsRunning] = false;
  162. m_StoppedStatus[StatusInfoKeys.MaxConnectionNumber] = Config.MaxConnectionNumber;
  163. if (m_PrevStatus != null)
  164. {
  165. m_StoppedStatus[StatusInfoKeys.Listeners] = m_PrevStatus[StatusInfoKeys.Listeners];
  166. }
  167. }
  168. return m_StoppedStatus;
  169. }
  170. public virtual StatusInfoCollection CollectServerStatus(StatusInfoCollection nodeStatus)
  171. {
  172. var appServer = AppServer;
  173. if (appServer == null)
  174. {
  175. var stoppedStatus = GetStoppedStatus();
  176. stoppedStatus.CollectedTime = DateTime.Now;
  177. return stoppedStatus;
  178. }
  179. var currentStatus = appServer.CollectServerStatus(nodeStatus);
  180. m_PrevStatus = currentStatus;
  181. return currentStatus;
  182. }
  183. /// <summary>
  184. /// Obtains a lifetime service object to control the lifetime policy for this instance.
  185. /// Return null, never expired
  186. /// </summary>
  187. /// <returns>
  188. /// An object of type <see cref="T:System.Runtime.Remoting.Lifetime.ILease" /> 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 <see cref="P:System.Runtime.Remoting.Lifetime.LifetimeServices.LeaseManagerPollTime" /> property.
  189. /// </returns>
  190. /// <PermissionSet>
  191. /// <IPermission class="System.Security.Permissions.SecurityPermission, mscorlib, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" version="1" Flags="RemotingConfiguration, Infrastructure" />
  192. /// </PermissionSet>
  193. public override object InitializeLifetimeService()
  194. {
  195. return null;
  196. }
  197. public void Dispose()
  198. {
  199. Dispose(true);
  200. // Use SupressFinalize in case a subclass
  201. // of this type implements a finalizer.
  202. GC.SuppressFinalize(this);
  203. }
  204. protected virtual void Dispose(bool disposing)
  205. {
  206. Stop();
  207. }
  208. ~IsolationAppServer()
  209. {
  210. Dispose(false);
  211. }
  212. public event EventHandler<SuperSocket.Common.ErrorEventArgs> ExceptionThrown;
  213. protected void OnExceptionThrown(Exception exc)
  214. {
  215. var handler = ExceptionThrown;
  216. if (handler == null)
  217. return;
  218. handler(this, new SuperSocket.Common.ErrorEventArgs(exc));
  219. }
  220. public void TransferSystemMessage(string messageType, object messageData)
  221. {
  222. var appServer = AppServer;
  223. if (appServer == null)
  224. OnExceptionThrown(new Exception("You cannot send system message to the instance who is not started."));
  225. appServer.TransferSystemMessage(messageType, messageData);
  226. }
  227. }
  228. }