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 applicationSessions = new MappingBTree((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(); 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("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> pluginInstances = new Dictionary>(); public void RegisterPluginInstance(PC pluginInstance) => RegisterPluginInstance(typeof(PC),pluginInstance); public void RegisterPluginInstance(Type type,object pluginInstance) { if (!pluginInstances.ContainsKey(type)) pluginInstances.Add(type, new List()); if (!pluginInstances[type].Contains(pluginInstance)) pluginInstances[type].Add(pluginInstance); } public IEnumerable GetPluginInstances() { 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()); } } }