Initial Commit
commit
fd109766a8
|
@ -0,0 +1,41 @@
|
||||||
|
# Autosave files
|
||||||
|
*~
|
||||||
|
|
||||||
|
# build
|
||||||
|
[Oo]bj/
|
||||||
|
[Bb]in/
|
||||||
|
packages/
|
||||||
|
TestResults/
|
||||||
|
|
||||||
|
# globs
|
||||||
|
Makefile.in
|
||||||
|
*.DS_Store
|
||||||
|
*.sln.cache
|
||||||
|
*.suo
|
||||||
|
*.cache
|
||||||
|
*.pidb
|
||||||
|
*.userprefs
|
||||||
|
*.usertasks
|
||||||
|
config.log
|
||||||
|
config.make
|
||||||
|
config.status
|
||||||
|
aclocal.m4
|
||||||
|
install-sh
|
||||||
|
autom4te.cache/
|
||||||
|
*.user
|
||||||
|
*.tar.gz
|
||||||
|
tarballs/
|
||||||
|
test-results/
|
||||||
|
Thumbs.db
|
||||||
|
.vs/
|
||||||
|
|
||||||
|
# Mac bundle stuff
|
||||||
|
*.dmg
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# resharper
|
||||||
|
*_Resharper.*
|
||||||
|
*.Resharper
|
||||||
|
|
||||||
|
# dotCover
|
||||||
|
*.dotCover
|
|
@ -0,0 +1,127 @@
|
||||||
|
using System;
|
||||||
|
using ln.http;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Linq;
|
||||||
|
using ln.logging;
|
||||||
|
using ln.types;
|
||||||
|
using System.Net;
|
||||||
|
using ln.application.service;
|
||||||
|
using ln.http.resources;
|
||||||
|
|
||||||
|
namespace ln.application
|
||||||
|
{
|
||||||
|
public class Application : IApplicationInterface
|
||||||
|
{
|
||||||
|
public ArgumentContainer Arguments { get; protected set; }
|
||||||
|
public HTTPServer HttpServer { get; private set; }
|
||||||
|
|
||||||
|
public ServiceContainer ServiceContainer { get; }
|
||||||
|
public ResourceApplication HTTPApplication { get; private set; }
|
||||||
|
|
||||||
|
public MemoryLogger MemoryLogger { get; }
|
||||||
|
|
||||||
|
public Application()
|
||||||
|
{
|
||||||
|
MemoryLogger = new MemoryLogger(8192);
|
||||||
|
Logger.Default.Backends.Add(MemoryLogger);
|
||||||
|
|
||||||
|
Arguments = new ArgumentContainer()
|
||||||
|
.Add((char)0, "log-level", "INFO")
|
||||||
|
.Add('l', "http-listen","0.0.0.0")
|
||||||
|
.Add('p', "http-port", "8080");
|
||||||
|
|
||||||
|
ServiceContainer = new ServiceContainer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void PrepareStart()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start(String[] arguments)
|
||||||
|
{
|
||||||
|
Arguments.Parse(arguments);
|
||||||
|
Logger.ConsoleLogger.MaxLogLevel = (LogLevel)Enum.Parse(typeof(LogLevel), Arguments["log-level"].Value);
|
||||||
|
|
||||||
|
/* Startup Sequence */
|
||||||
|
|
||||||
|
Logging.Log(LogLevel.INFO, "Calling PrepareStart()");
|
||||||
|
PrepareStart();
|
||||||
|
|
||||||
|
/* HTTP Server */
|
||||||
|
Logging.Log(LogLevel.INFO, "Start: HTTPServer on {0}:{1}", Arguments['l'].Value, Arguments['p'].IntegerValue);
|
||||||
|
HttpServer = new HTTPServer();
|
||||||
|
HttpServer.AddEndpoint(new System.Net.IPEndPoint(
|
||||||
|
IPAddress.Parse(Arguments['l'].Value),
|
||||||
|
Arguments['p'].IntegerValue
|
||||||
|
));
|
||||||
|
|
||||||
|
HttpServer.Start();
|
||||||
|
HTTPApplication = new ResourceApplication();
|
||||||
|
HttpServer.DefaultApplication = HTTPApplication;
|
||||||
|
|
||||||
|
|
||||||
|
/* Application Services */
|
||||||
|
foreach (ServiceDefinition serviceDefinition in ServiceContainer)
|
||||||
|
{
|
||||||
|
if (serviceDefinition.AutoStart)
|
||||||
|
ServiceContainer.Start(serviceDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
Logging.Log(LogLevel.INFO, "Application shutdown requested");
|
||||||
|
|
||||||
|
/* Application Services */
|
||||||
|
foreach (ServiceDefinition serviceDefinition in ServiceContainer)
|
||||||
|
{
|
||||||
|
if (serviceDefinition.IsAlive)
|
||||||
|
{
|
||||||
|
ServiceContainer.Stop(serviceDefinition);
|
||||||
|
if (serviceDefinition.IsAlive)
|
||||||
|
throw new Exception("application service could not be stopped");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* HTTP Server */
|
||||||
|
Logging.Log(LogLevel.INFO, "Stopping HTTP server");
|
||||||
|
HttpServer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Plugin Classes
|
||||||
|
*/
|
||||||
|
Dictionary<Type, List<object>> pluginInstances = new Dictionary<Type, List<object>>();
|
||||||
|
|
||||||
|
public void RegisterPluginInstance<PC>(PC pluginInstance) => RegisterPluginInstance(typeof(PC),pluginInstance);
|
||||||
|
public void RegisterPluginInstance(Type type,object pluginInstance)
|
||||||
|
{
|
||||||
|
if (!pluginInstances.ContainsKey(type))
|
||||||
|
pluginInstances.Add(type, new List<object>());
|
||||||
|
|
||||||
|
if (!pluginInstances[type].Contains(pluginInstance))
|
||||||
|
pluginInstances[type].Add(pluginInstance);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<PC> GetPluginInstances<PC>()
|
||||||
|
{
|
||||||
|
Type pluginType = typeof(PC);
|
||||||
|
if (!pluginInstances.ContainsKey(pluginType))
|
||||||
|
return new PC[0];
|
||||||
|
|
||||||
|
return pluginInstances[pluginType].Select((ut) => (PC)ut);
|
||||||
|
}
|
||||||
|
public IEnumerable GetPluginInstances(Type pluginType)
|
||||||
|
{
|
||||||
|
if (!pluginInstances.ContainsKey(pluginType))
|
||||||
|
return new object[0];
|
||||||
|
|
||||||
|
return pluginInstances[pluginType];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using ln.application.service;
|
||||||
|
using ln.http.resources;
|
||||||
|
using ln.http;
|
||||||
|
using ln.types;
|
||||||
|
namespace ln.application
|
||||||
|
{
|
||||||
|
public interface IApplicationInterface
|
||||||
|
{
|
||||||
|
ArgumentContainer Arguments { get; }
|
||||||
|
|
||||||
|
HTTPServer HttpServer { get; }
|
||||||
|
ResourceApplication HTTPApplication { get; }
|
||||||
|
ServiceContainer ServiceContainer { get; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
// Information about this assembly is defined by the following attributes.
|
||||||
|
// Change them to the values specific to your project.
|
||||||
|
|
||||||
|
[assembly: AssemblyTitle("ln.application")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("")]
|
||||||
|
[assembly: AssemblyCopyright("")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
|
||||||
|
// The form "{Major}.{Minor}.*" will automatically update the build and revision,
|
||||||
|
// and "{Major}.{Minor}.{Build}.*" will update just the revision.
|
||||||
|
|
||||||
|
[assembly: AssemblyVersion("1.0.*")]
|
||||||
|
|
||||||
|
// The following attributes are used to specify the signing key for the assembly,
|
||||||
|
// if desired. See the Mono documentation for more information about signing.
|
||||||
|
|
||||||
|
//[assembly: AssemblyDelaySign(false)]
|
||||||
|
//[assembly: AssemblyKeyFile("")]
|
|
@ -0,0 +1,62 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{44AA3A50-7214-47F2-9D60-6FF34C0FE6D3}</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<RootNamespace>ln.application</RootNamespace>
|
||||||
|
<AssemblyName>ln.application</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<ConsolePause>false</ConsolePause>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release</OutputPath>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
<ConsolePause>false</ConsolePause>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Application.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
<Compile Include="IApplicationInterface.cs" />
|
||||||
|
<Compile Include="service\ServiceDefinition.cs" />
|
||||||
|
<Compile Include="service\ServiceContainer.cs" />
|
||||||
|
<Compile Include="service\ApplicationServiceBase.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\ln.types\ln.types.csproj">
|
||||||
|
<Project>{8D9AB9A5-E513-4BA7-A450-534F6456BF28}</Project>
|
||||||
|
<Name>ln.types</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\ln.logging\ln.logging.csproj">
|
||||||
|
<Project>{D471A566-9FB6-41B2-A777-3C32874ECD0E}</Project>
|
||||||
|
<Name>ln.logging</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\ln.http.resources\ln.http.resources.csproj">
|
||||||
|
<Project>{F9086FE4-8925-42FF-A59C-607341604293}</Project>
|
||||||
|
<Name>ln.http.resources</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\ln.http\ln.http.csproj">
|
||||||
|
<Project>{CEEEEB41-3059-46A2-A871-2ADE22C013D9}</Project>
|
||||||
|
<Name>ln.http</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="service\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
|
@ -0,0 +1,108 @@
|
||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using ln.logging;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace ln.application.service
|
||||||
|
{
|
||||||
|
public abstract class ApplicationServiceBase : IDisposable
|
||||||
|
{
|
||||||
|
public int TimeOut { get; set; } = 10000;
|
||||||
|
|
||||||
|
public String ServiceName { get; protected set; }
|
||||||
|
public virtual bool IsAlive => ((ServiceThread != null) && ServiceThread.IsAlive);
|
||||||
|
|
||||||
|
public bool StopRequested { get; protected set; }
|
||||||
|
public Thread ServiceThread { get; protected set; }
|
||||||
|
|
||||||
|
public string ServiceStateText { get; protected set; }
|
||||||
|
|
||||||
|
public IApplicationInterface CurrentApplicationInterface { get; protected set; }
|
||||||
|
|
||||||
|
public Type[] DependingServiceTypes => dependingServiceTypes.ToArray();
|
||||||
|
HashSet<Type> dependingServiceTypes = new HashSet<Type>();
|
||||||
|
|
||||||
|
public ApplicationServiceBase(String serviceName)
|
||||||
|
{
|
||||||
|
ServiceName = serviceName;
|
||||||
|
ServiceStateText = "Initialized";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
ServiceStateText = "Disposed";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void DependOnService<S>() => dependingServiceTypes.Add(typeof(S));
|
||||||
|
|
||||||
|
public T Dependency<T>() where T : ApplicationServiceBase
|
||||||
|
{
|
||||||
|
T serviceBase = (T)CurrentApplicationInterface.ServiceContainer[typeof(T)].ServiceBase;
|
||||||
|
if (serviceBase == null)
|
||||||
|
throw new EntryPointNotFoundException(String.Format("depending service not found: {0}",typeof(T).ToString()));
|
||||||
|
|
||||||
|
return serviceBase;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void ServiceMain(IApplicationInterface applicationInterface) => throw new NotImplementedException();
|
||||||
|
|
||||||
|
public virtual bool Start(IApplicationInterface applicationInterface, String[] arguments)
|
||||||
|
{
|
||||||
|
if (IsAlive)
|
||||||
|
throw new NotSupportedException("Service is already alive");
|
||||||
|
|
||||||
|
CurrentApplicationInterface = applicationInterface;
|
||||||
|
|
||||||
|
foreach (Type dep in dependingServiceTypes)
|
||||||
|
{
|
||||||
|
ServiceDefinition depService = CurrentApplicationInterface.ServiceContainer[dep];
|
||||||
|
if (!depService.IsAlive)
|
||||||
|
{
|
||||||
|
CurrentApplicationInterface.ServiceContainer.Start(depService);
|
||||||
|
if (!depService.IsAlive)
|
||||||
|
{
|
||||||
|
Logging.Log(LogLevel.ERROR, "service {0} could not start depending service {1}", ServiceName, depService.ServiceClassName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
StopRequested = false;
|
||||||
|
ServiceThread = new Thread(() => ServiceMain(applicationInterface));
|
||||||
|
ServiceThread.Start();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual bool Stop() => Stop(false);
|
||||||
|
public virtual bool Stop(bool force)
|
||||||
|
{
|
||||||
|
if (IsAlive)
|
||||||
|
{
|
||||||
|
StopRequested = true;
|
||||||
|
lock (ServiceThread)
|
||||||
|
{
|
||||||
|
Monitor.PulseAll(ServiceThread);
|
||||||
|
}
|
||||||
|
ServiceThread.Join(TimeOut);
|
||||||
|
if (IsAlive && force)
|
||||||
|
{
|
||||||
|
Logging.Log(LogLevel.INFO, "Service did not shutdown, enforcing {0}",ServiceName);
|
||||||
|
ServiceThread.Abort();
|
||||||
|
ServiceThread.Join(TimeOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ServiceThread.IsAlive)
|
||||||
|
CurrentApplicationInterface = null;
|
||||||
|
|
||||||
|
return !ServiceThread.IsAlive;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
namespace ln.application.service
|
||||||
|
{
|
||||||
|
public class ServiceContainer : IEnumerable<ServiceDefinition>
|
||||||
|
{
|
||||||
|
public Application Application { get; }
|
||||||
|
|
||||||
|
HashSet<ServiceDefinition> serviceDefinitions = new HashSet<ServiceDefinition>();
|
||||||
|
|
||||||
|
public ServiceContainer(Application application)
|
||||||
|
{
|
||||||
|
Application = application;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(ServiceDefinition serviceDefinition)
|
||||||
|
{
|
||||||
|
serviceDefinitions.Add(serviceDefinition);
|
||||||
|
}
|
||||||
|
public void Remove(ServiceDefinition serviceDefinition)
|
||||||
|
{
|
||||||
|
serviceDefinitions.Remove(serviceDefinition);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ServiceDefinition this[string serviceClassName]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
foreach (ServiceDefinition serviceDefinition in serviceDefinitions)
|
||||||
|
{
|
||||||
|
if (serviceDefinition.ServiceClassName.Equals(serviceClassName))
|
||||||
|
return serviceDefinition;
|
||||||
|
}
|
||||||
|
throw new KeyNotFoundException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public ServiceDefinition this[string assemblyName,string serviceClassName]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
foreach (ServiceDefinition serviceDefinition in serviceDefinitions)
|
||||||
|
{
|
||||||
|
if (serviceDefinition.ServiceClassName.Equals(serviceClassName) && Object.Equals(serviceDefinition.AssemblyName,assemblyName))
|
||||||
|
return serviceDefinition;
|
||||||
|
}
|
||||||
|
throw new KeyNotFoundException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public ServiceDefinition this[Type serviceType]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this[serviceType.Assembly.FullName,serviceType.FullName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Start(ServiceDefinition serviceDefinition)
|
||||||
|
{
|
||||||
|
if (!serviceDefinitions.Contains(serviceDefinition))
|
||||||
|
throw new NotSupportedException("ServiceDefinition not known to ServiceContainer");
|
||||||
|
|
||||||
|
ServiceDefinition sd = this[serviceDefinition.AssemblyName, serviceDefinition.ServiceClassName];
|
||||||
|
sd.Start(this.Application);
|
||||||
|
}
|
||||||
|
public void Stop(ServiceDefinition serviceDefinition)
|
||||||
|
{
|
||||||
|
if (!serviceDefinitions.Contains(serviceDefinition))
|
||||||
|
throw new NotSupportedException("ServiceDefinition not known to ServiceContainer");
|
||||||
|
|
||||||
|
ServiceDefinition sd = this[serviceDefinition.AssemblyName, serviceDefinition.ServiceClassName];
|
||||||
|
sd.Stop();
|
||||||
|
}
|
||||||
|
public void Load(ServiceDefinition serviceDefinition)
|
||||||
|
{
|
||||||
|
if (!serviceDefinitions.Contains(serviceDefinition))
|
||||||
|
throw new NotSupportedException("ServiceDefinition not known to ServiceContainer");
|
||||||
|
|
||||||
|
ServiceDefinition sd = this[serviceDefinition.AssemblyName, serviceDefinition.ServiceClassName];
|
||||||
|
sd.Load();
|
||||||
|
}
|
||||||
|
public void Unload(ServiceDefinition serviceDefinition)
|
||||||
|
{
|
||||||
|
if (!serviceDefinitions.Contains(serviceDefinition))
|
||||||
|
throw new NotSupportedException("ServiceDefinition not known to ServiceContainer");
|
||||||
|
|
||||||
|
ServiceDefinition sd = this[serviceDefinition.AssemblyName, serviceDefinition.ServiceClassName];
|
||||||
|
sd.Unload();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public IEnumerator<ServiceDefinition> GetEnumerator()
|
||||||
|
{
|
||||||
|
return ((IEnumerable<ServiceDefinition>)serviceDefinitions).GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return ((IEnumerable<ServiceDefinition>)serviceDefinitions).GetEnumerator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,119 @@
|
||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using ln.logging;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
namespace ln.application.service
|
||||||
|
{
|
||||||
|
public class ServiceDefinition
|
||||||
|
{
|
||||||
|
public String AssemblyName { get; }
|
||||||
|
public String ServiceClassName { get; }
|
||||||
|
public bool AutoStart { get; set; }
|
||||||
|
|
||||||
|
public ApplicationServiceBase ServiceBase { get; private set; }
|
||||||
|
|
||||||
|
public bool IsLoaded => ServiceBase != null;
|
||||||
|
public bool IsAlive => IsLoaded && ServiceBase.IsAlive;
|
||||||
|
|
||||||
|
Assembly serviceAssembly;
|
||||||
|
Type serviceType;
|
||||||
|
|
||||||
|
public ServiceDefinition(String assemblyName, string serviceClassName)
|
||||||
|
{
|
||||||
|
AssemblyName = assemblyName;
|
||||||
|
ServiceClassName = serviceClassName;
|
||||||
|
}
|
||||||
|
public ServiceDefinition(string serviceClassName)
|
||||||
|
{
|
||||||
|
AssemblyName = null;
|
||||||
|
ServiceClassName = serviceClassName;
|
||||||
|
}
|
||||||
|
public static ServiceDefinition From<S>() => From<S>(true);
|
||||||
|
public static ServiceDefinition From<S>(bool autoStart)
|
||||||
|
{
|
||||||
|
Type st = typeof(S);
|
||||||
|
ServiceDefinition sd = new ServiceDefinition(
|
||||||
|
st.Assembly.FullName,
|
||||||
|
st.FullName
|
||||||
|
);
|
||||||
|
sd.AutoStart = autoStart;
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Load()
|
||||||
|
{
|
||||||
|
if (IsLoaded)
|
||||||
|
throw new NotSupportedException(String.Format("Service {0} [{1}] is already loaded",ServiceClassName,AssemblyName));
|
||||||
|
|
||||||
|
if (AssemblyName != null)
|
||||||
|
serviceAssembly = Assembly.Load(AssemblyName);
|
||||||
|
|
||||||
|
serviceType = FinalAssembly.GetType(ServiceClassName);
|
||||||
|
if (serviceType == null)
|
||||||
|
throw new EntryPointNotFoundException(String.Format("could not get type {0}",ServiceClassName));
|
||||||
|
|
||||||
|
if (!serviceType.IsSubclassOf(typeof(ApplicationServiceBase)))
|
||||||
|
throw new NotSupportedException(String.Format("application service type must derive from ApplicationServiceBase"));
|
||||||
|
|
||||||
|
ServiceBase = (ApplicationServiceBase)Activator.CreateInstance(serviceType);
|
||||||
|
}
|
||||||
|
public void Unload() => Unload(false);
|
||||||
|
public void Unload(bool force)
|
||||||
|
{
|
||||||
|
if (!IsLoaded)
|
||||||
|
throw new NotSupportedException(String.Format("Service {0} [{1}] is not loaded", ServiceClassName, AssemblyName));
|
||||||
|
|
||||||
|
if (!force && IsAlive)
|
||||||
|
throw new NotSupportedException(String.Format("Service {0} [{1}] still alive", ServiceClassName, AssemblyName));
|
||||||
|
|
||||||
|
ServiceBase.Dispose();
|
||||||
|
|
||||||
|
ServiceBase = null;
|
||||||
|
serviceType = null;
|
||||||
|
serviceAssembly = null;
|
||||||
|
}
|
||||||
|
public void Start(IApplicationInterface applicationInterface)
|
||||||
|
{
|
||||||
|
if (!IsLoaded)
|
||||||
|
Load();
|
||||||
|
|
||||||
|
Logging.Log(LogLevel.INFO, "service: starting {0} [{1}]", ServiceClassName, FinalAssembly.GetName().Name);
|
||||||
|
|
||||||
|
if (ServiceBase.Start(applicationInterface,new string[0]))
|
||||||
|
Logging.Log(LogLevel.INFO, "service: started {0} [{1}]", ServiceClassName, FinalAssembly.GetName().Name);
|
||||||
|
else
|
||||||
|
Logging.Log(LogLevel.ERROR, "service: failed {0} [{1}]", ServiceClassName, FinalAssembly.GetName().Name);
|
||||||
|
}
|
||||||
|
public void Stop()
|
||||||
|
{
|
||||||
|
if (IsAlive)
|
||||||
|
{
|
||||||
|
Logging.Log(LogLevel.INFO, "service: stopping {0} [{1}]", ServiceClassName, FinalAssembly.GetName().Name);
|
||||||
|
|
||||||
|
if (ServiceBase.Stop())
|
||||||
|
Logging.Log(LogLevel.INFO, "service: stopped {0} [{1}]", ServiceClassName, FinalAssembly.GetName().Name);
|
||||||
|
else
|
||||||
|
Logging.Log(LogLevel.ERROR, "service: stopfail {0} [{1}]", ServiceClassName, FinalAssembly.GetName().Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Assembly FinalAssembly => serviceAssembly != null ? serviceAssembly : Assembly.GetEntryAssembly();
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return (AssemblyName != null ? AssemblyName.GetHashCode() : 0) ^ ServiceClassName.GetHashCode();
|
||||||
|
}
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj is ServiceDefinition)
|
||||||
|
{
|
||||||
|
ServiceDefinition other = obj as ServiceDefinition;
|
||||||
|
return Object.Equals(AssemblyName, other.AssemblyName) && ServiceClassName.Equals(other.ServiceClassName);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue