/// <summary> /// Creates a server configuration from a CLI config instance /// </summary> /// <returns>The server configuration.</returns> /// <param name="config">The CLI config instance.</param> public static ServerConfig ValidateConfig(CLIServerConfiguration config) { var cfg = CreateServerConfig(config); // Set up the module context var ctx = LoaderContext.StartContext(); cfg.LoaderContext = ctx; // Expose our configuration to allow modules to call back, // beware that these values should never be reported to the client // as there might be proxies in front which will make them useless // to clients not running on the local machine if (config.ListenHttp) { var parsedip = ParseUtil.ParseIPAddress(config.HttpAddress); var ip = parsedip == IPAddress.Any ? "127.0.0.1" : parsedip.ToString(); Environment.SetEnvironmentVariable("CEEN_SELF_HTTP_URL", "http://" + ip + ":" + config.HttpPort); } if (config.ListenHttps) { var parsedip = ParseUtil.ParseIPAddress(config.HttpsAddress); var ip = parsedip == IPAddress.Any ? "127.0.0.1" : parsedip.ToString(); Environment.SetEnvironmentVariable("CEEN_SELF_HTTPS_URL", "http://" + ip + ":" + config.HttpsPort); } if (config.AutoLoadAssemblies) { // Workaround for unittests not providing EntryAssembly var callingasm = Assembly.GetEntryAssembly(); var callingdir = callingasm == null ? null : Path.GetDirectoryName(callingasm.Location); var paths = (config.Assemblypath ?? string.Empty) .Split(new char[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries) .Union(new[] { config.Basepath, callingdir }) .Where(x => !string.IsNullOrWhiteSpace(x) && Directory.Exists(x)) .Distinct(); foreach (var p in paths) { foreach (var file in Directory.GetFiles(p, "*.*", SearchOption.TopDirectoryOnly)) { if (file.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) || file.EndsWith(".exe", StringComparison.OrdinalIgnoreCase)) { try { Assembly.LoadFrom(file); } catch { } } } } var ceenpath = Path.GetDirectoryName(typeof(CLIServerConfiguration).Assembly.Location); if (Directory.Exists(ceenpath)) { foreach (var dll in Directory.GetFiles(ceenpath, "Ceen.*.dll", SearchOption.TopDirectoryOnly)) { try { Assembly.LoadFrom(dll); } catch { } } } } if (config.Loggers != null) { foreach (var logger in config.Loggers) { var inst = CreateInstance(logger.Classname, logger.ConstructorArguments, typeof(ILogger)); if (logger.Options != null) { SetProperties(inst, logger.Options); } if (inst is IWithSetup mse) { mse.AfterConfigure(); } cfg.AddLogger((ILogger)inst); } } if (config.Modules != null) { foreach (var module in config.Modules) { object handler; var moduletype = ResolveType(module.Classname); handler = CreateInstance(moduletype, module.ConstructorArguments, typeof(IModule)); if (module.Options != null) { SetProperties(handler, module.Options); } if (handler is IWithSetup mse) { mse.AfterConfigure(); } cfg.AddModule((IModule)handler); } } if (config.PostProcessors != null) { foreach (var postProcessor in config.PostProcessors) { var inst = CreateInstance(postProcessor.Classname, postProcessor.ConstructorArguments, typeof(IPostProcessor)); if (postProcessor.Options != null) { SetProperties(inst, postProcessor.Options); } if (inst is IWithSetup mse) { mse.AfterConfigure(); } cfg.AddPostProcessor((IPostProcessor)inst); } } if (config.Routes != null) { Ceen.Mvc.ManualRoutingController wirecontroller = null; Ceen.Mvc.ControllerRouterConfig wirecontrollerconfig = null; foreach (var route in config.Routes) { // If we have a wired controller, and a non-wire item // add it now to ensure the order is maintained if (wirecontroller != null && !(route is WiredRouteDefinition)) { cfg.AddRoute(wirecontroller.ToRoute(wirecontrollerconfig)); wirecontroller = null; } // Check for wireups if (route is WiredRouteDefinition wired) { // Make a new manual router, if none is present or if we add one if (wirecontroller == null || (wired.RoutePrefix == null)) { // Add any previous wireup to the routes if (wirecontroller != null) { cfg.AddRoute(wirecontroller.ToRoute(wirecontrollerconfig)); } wirecontrollerconfig = new Ceen.Mvc.ControllerRouterConfig(); if (route.Options != null) { SetProperties(wirecontrollerconfig, route.Options); } wirecontroller = new Ceen.Mvc.ManualRoutingController(); } if (wired.Verbs == null) { var itemtype = ResolveType(wired.Classname); wirecontroller.WireController(itemtype, wired.RoutePrefix, wirecontrollerconfig); } else { var ix = wired.Classname.LastIndexOf('.'); var classname = wired.Classname.Substring(0, ix); var methodname = wired.Classname.Substring(ix + 1); var itemtype = ResolveType(classname); var argumenttypes = wired.ConstructorArguments.Select(x => ResolveType(x)).ToArray(); if (argumenttypes.Any(x => x == null)) { throw new Exception($"Cannot resolve type argument {argumenttypes.Select((a, b) => a == null ? wired.ConstructorArguments[b] : null).Where(x => x != null).First()}"); } wirecontroller.Wire(itemtype, wired.Verbs + " " + wired.RoutePrefix, methodname, argumenttypes); } } // Check if this is a module else if (route.RoutePrefix != null) { object handler; var moduletype = ResolveType(route.Classname); if (typeof(Ceen.Httpd.Handler.FileHandler).IsAssignableFrom(moduletype)) { Func <IHttpRequest, string, string> mimehandler = null; if (config.MimeTypes != null && config.MimeTypes.Count > 0) { string default_mimetype; config.MimeTypes.TryGetValue("*", out default_mimetype); if (string.IsNullOrWhiteSpace(default_mimetype)) { default_mimetype = null; } if (config.IgnoreDefaultMimeTypes) { mimehandler = (req, mappedpath) => { var ext = Path.GetExtension(mappedpath).ToLowerInvariant(); string mime; config.MimeTypes.TryGetValue(ext, out mime); if (default_mimetype != null && string.IsNullOrWhiteSpace(mime)) { return(default_mimetype); } return(mime); }; } else { mimehandler = (req, mappedpath) => { var ext = Path.GetExtension(mappedpath).ToLowerInvariant(); string mime; config.MimeTypes.TryGetValue(ext, out mime); if (!string.IsNullOrWhiteSpace(mime)) { return(mime); } else if (default_mimetype != null && string.IsNullOrWhiteSpace(mime)) { return(default_mimetype); } else { return(Ceen.Httpd.Handler.FileHandler.DefaultMimeTypes(mappedpath)); } }; } } else if (config.IgnoreDefaultMimeTypes) { mimehandler = (req, path) => null; } handler = Activator.CreateInstance( moduletype, ExpandEnvironmentVariables(route.ConstructorArguments.First()), mimehandler ); if (config.IndexDocuments.Count != 0) { if (route.Options.ContainsKey(nameof(Handler.FileHandler.IndexDocuments))) { throw new Exception($"Cannot use both the `Index` option and {nameof(Handler.FileHandler.IndexDocuments)} in the configuration for {moduletype.FullName}"); } route.Options[nameof(Handler.FileHandler.IndexDocuments)] = string.Join(", ", config.IndexDocuments.Select(x => $"\"{x}\"")); } } else { handler = CreateInstance(moduletype, route.ConstructorArguments, typeof(IHttpModule)); } if (route.Options != null) { SetProperties(handler, route.Options); } if (handler is IWithSetup mse) { mse.AfterConfigure(); } if (string.IsNullOrWhiteSpace(route.RoutePrefix)) { cfg.AddRoute((IHttpModule)handler); } else { cfg.AddRoute(route.RoutePrefix, (IHttpModule)handler); } } // Otherwise it is automatic routing of an assembly else { var assembly = Assembly.Load(route.Assembly); if (assembly == null) { throw new Exception($"Failed to load assembly {route.Assembly}"); } Type defaulttype = null; if (!string.IsNullOrWhiteSpace(route.Classname)) { defaulttype = assembly.GetType(route.Classname, false); if (defaulttype == null) { throw new Exception($"Failed to find class {route.Classname} in {route.Assembly}"); } } var rt = new Ceen.Mvc.ControllerRouterConfig(defaulttype); if (route.Options != null) { SetProperties(rt, route.Options); } cfg.AddRoute(new Ceen.Mvc.ControllerRouter(rt, assembly)); } } // If we have a wired controller, add it if (wirecontroller != null) { cfg.AddRoute(wirecontroller.ToRoute(wirecontrollerconfig)); } } ctx.Freeze(); return(cfg); }
/// <summary> /// Creates a route instance for a manual routing controller /// </summary> /// <param name="self">The manual routing controller</param> /// <param name="config">The config to use</param> /// <returns>The controller</returns> public static Ceen.Mvc.ControllerRouter ToRoute(this Ceen.Mvc.ManualRoutingController self, Ceen.Mvc.ControllerRouterConfig config = null) => new Mvc.ControllerRouter( config ?? new Mvc.ControllerRouterConfig(), self );