ln.application/Application.cs

241 lines
8.1 KiB
C#

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;
using ln.types.btree;
using ln.types.rpc;
using ln.application.slots;
using ln.identities;
using ln.http.session;
using ln.json.mapping;
using ln.application.json;
using System.Reflection;
namespace ln.application
{
public class Application : ResourceApplication
{
public String ApplicationName { get; protected set; } = "ln.application base";
public ArgumentContainer Arguments { get; protected set; }
public HTTPServer HttpServer { get; private set; }
bool usesDedicatedHttpServer = false;
public ServiceContainer ServiceContainer { get; }
public MemoryLogger MemoryLogger { get; }
public int ApplicationContextTimeout { get; set; } = 1200;
public RPCContainer RPCContainer { get; } = new RPCContainer();
public BinarySlotContainer BinarySlots { get; } = new BinarySlotContainer();
public IIdentityProvider IdentityProvider { get; protected set; }
MappingBTree<Guid, ApplicationSession> applicationSessions = new MappingBTree<Guid, ApplicationSession>((x)=>x.SessionID);
public Application(HTTPServer httpServer, IIdentityProvider identityProvider,RPCContainer rpcContainer)
{
HttpServer = httpServer;
IdentityProvider = identityProvider;
RPCContainer = rpcContainer ?? new RPCContainer(CheckRPCAccess);
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);
RPCContainer.Add("",new ApplicationRPC(this));
RPCContainer.Add("ServiceContainer", ServiceContainer.RPC);
}
public Application() :this(null,null,null) { }
public Application(IIdentityProvider identityProvider) : this(null,identityProvider,null) { }
bool CheckRPCAccess(RPCContainer container, RPCContainer.RPCModule module, System.Reflection.MethodInfo method)
{
RequireAttribute require = method.GetCustomAttribute<RequireAttribute>();
if (require != null)
{
Identity currentIdentity = ApplicationSession.CurrentSession?.SessionIdentity;
if (currentIdentity == null)
throw new AuthenticationNeeded();
Guid requiredUID = require.IdentityUniqueID;
if (require.IdentityName != null)
{
requiredUID = currentIdentity.IdentityProvider.GetIdentity(require.IdentityName)?.UniqueID ?? throw new KeyNotFoundException();
}
return currentIdentity.AssignedRoles.HasRole(requiredUID, require.Role);
}
return true;
}
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 */
if (HttpServer == null)
{
Logging.Log(LogLevel.INFO, "Start: HTTPServer on {0}:{1}", Arguments['l'].Value, Arguments['p'].IntegerValue);
HttpServer = new HTTPServer(new System.Net.IPEndPoint(
IPAddress.Parse(Arguments['l'].Value),
Arguments['p'].IntegerValue
),
HttpRouter
);
HttpServer.Start();
usesDedicatedHttpServer = true;
}
/* Application Services */
foreach (ServiceDefinition serviceDefinition in ServiceContainer)
{
if (serviceDefinition.AutoStart && !serviceDefinition.IsAlive)
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 */
if (usesDedicatedHttpServer)
{
Logging.Log(LogLevel.INFO, "Stopping HTTP server");
HttpServer.Stop();
}
}
public virtual ApplicationSession CreateApplicationSession() => new ApplicationSession(this);
public ApplicationSession GetApplicationSession(Session session)
{
ApplicationSession applicationSession = session.Get<ApplicationSession>("LNApplicationSession");
if (applicationSession == null)
{
applicationSession = CreateApplicationSession();
applicationSessions.Add(applicationSession);
session["LNApplicationSession"] = applicationSession;
}
return applicationSession;
}
public ApplicationSession GetApplicationSession() => GetApplicationSession(Guid.Empty);
public ApplicationSession GetApplicationSession(Guid contextID)
{
ApplicationSession applicationSession = null;
if (!applicationSessions.TryGet(contextID,out applicationSession))
{
while (true)
{
applicationSession = CreateApplicationSession();
if (!applicationSessions.ContainsKey(applicationSession.SessionID))
{
applicationSessions.Add(applicationSession);
break;
}
}
}
return applicationSession;
}
public virtual object ProcessMessage(object message)
{
//Application.BinarySlots.RequestSlot(message as SlotRequest);
return null;
}
public virtual Identity Authenticate(string username,object prove)
{
return null;
}
public void CleanupApplicationContexts()
{
foreach (ApplicationSession applicationContext in applicationSessions.ToArray())
{
if (applicationContext.Untouched > TimeSpan.FromSeconds(ApplicationContextTimeout))
applicationSessions.RemoveKey(applicationContext.SessionID);
}
}
/*
* 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];
}
static Application()
{
JSONMapper.DefaultMapper.Add(new JSONIdentityMapping());
}
}
}