diff --git a/SharpBoss.Logging/Logger.cs b/SharpBoss.Logging/Logger.cs
index 4862ff5..51c04a1 100644
--- a/SharpBoss.Logging/Logger.cs
+++ b/SharpBoss.Logging/Logger.cs
@@ -6,110 +6,127 @@
using NLog.Config;
using NLog.Targets;
-namespace SharpBoss.Logging {
- ///
- /// Logger class
- ///
- public static class Logger {
- private static readonly string _datePattern = "yyyy-MM-dd";
- private static readonly string _filenamePattern = "sharpboss_{0}.txt";
- private static readonly string _environmentVariable = "SHARPBOSS_CONFIG_FILENAME";
- private static readonly string _configKey = "SHARPBOSS_CONFIG_FILENAME";
-
- ///
- /// Retrieve Logger
- ///
- /// ILogger
- private static ILogger GetLogger () {
- var stackFrame = new StackFrame (2, true);
- var method = stackFrame.GetMethod ();
- var assembly = method.DeclaringType;
-
- LogManager.Configuration = GetConfig ();
-
- var loggingName = string.Format ("{0}::{1}", assembly.FullName, method.Name);
-
- return LogManager.GetLogger (loggingName);
- }
-
- ///
- /// Retrieve filename for Logging output
- ///
- /// Retrieve filename for Logging output
- private static string GetFileName () {
- var dateTime = DateTime.Now;
- var filename = string.Format (_filenamePattern, dateTime.ToString (_datePattern));
- var environmentVariable = Environment.GetEnvironmentVariable (_environmentVariable);
- var configValue = ConfigurationManager.AppSettings[_configKey];
-
- if (environmentVariable != null) {
- return environmentVariable;
- } else if (configValue != null) {
- return configValue;
- }
-
- return filename;
- }
-
- ///
- /// Get configuration for Log target
- ///
- /// NLog Configuration
- private static LoggingConfiguration GetConfig () {
- var config = new LoggingConfiguration ();
- var target = new FileTarget {
- FileName = GetFileName (),
- Layout = "${longdate} ${level:lowercase=true} [${logger}] ${message}",
- };
-
- config.AddRuleForAllLevels (target);
-
- return config;
- }
-
- ///
- /// Retrieve message with format
- ///
- /// Message to log
- /// Formatted message
- private static string GetMessage (string message) {
- return string.Format ("{0}", message);
- }
-
- ///
- /// Log message with info level
- ///
- /// Message to log
- public static void Info (string message) {
- var logger = GetLogger ();
- logger.Info (GetMessage (message));
- }
-
- ///
- /// Log message with debug level
- ///
- /// Message to log
- public static void Debug (string message) {
- var logger = GetLogger ();
- logger.Debug (GetMessage (message));
- }
-
- ///
- /// Log message with warning level
- ///
- /// Message to log
- public static void Warn (string message) {
- var logger = GetLogger ();
- logger.Warn (GetMessage (message));
- }
-
+namespace SharpBoss.Logging
+{
///
- /// Log message with error level
+ /// Logger class
///
- /// Message to log
- public static void Error (string message) {
- var logger = GetLogger ();
- logger.Error (GetMessage (message));
+ public static class Logger
+ {
+ private static readonly string _datePattern = "yyyy-MM-dd";
+ private static readonly string _filenamePattern = "sharpboss_{0}.txt";
+ private static readonly string _environmentVariable = "SHARPBOSS_CONFIG_FILENAME";
+ private static readonly string _configKey = "SHARPBOSS_CONFIG_FILENAME";
+
+ static readonly ILogger Log = LogManager.GetCurrentClassLogger();
+
+ ///
+ /// Retrieve Logger
+ ///
+ /// ILogger
+ private static ILogger GetLogger()
+ {
+ //var stackFrame = new StackFrame (2, true);
+ //var method = stackFrame.GetMethod ();
+ //var assembly = method.DeclaringType;
+
+ //LogManager.Configuration = GetConfig ();
+
+ //var loggingName = string.Format ("{0}::{1}", assembly.FullName, method.Name);
+
+ //return LogManager.GetLogger (loggingName);
+ return Log;
+ }
+
+ ///
+ /// Retrieve filename for Logging output
+ ///
+ /// Retrieve filename for Logging output
+ private static string GetFileName()
+ {
+ var dateTime = DateTime.Now;
+ var filename = string.Format(_filenamePattern, dateTime.ToString(_datePattern));
+ var environmentVariable = Environment.GetEnvironmentVariable(_environmentVariable);
+ var configValue = ConfigurationManager.AppSettings[_configKey];
+
+ if (environmentVariable != null)
+ {
+ return environmentVariable;
+ }
+ else if (configValue != null)
+ {
+ return configValue;
+ }
+
+ return filename;
+ }
+
+ ///
+ /// Get configuration for Log target
+ ///
+ /// NLog Configuration
+ private static LoggingConfiguration GetConfig()
+ {
+ var config = new LoggingConfiguration();
+ var target = new FileTarget
+ {
+ FileName = GetFileName(),
+ Layout = "${longdate} ${level:lowercase=true} [${logger}] ${message}",
+ };
+
+ config.AddRuleForAllLevels(target);
+
+ return config;
+ }
+
+ ///
+ /// Retrieve message with format
+ ///
+ /// Message to log
+ /// Formatted message
+ private static string GetMessage(string message)
+ {
+ return string.Format("{0}", message);
+ }
+
+ ///
+ /// Log message with info level
+ ///
+ /// Message to log
+ public static void Info(string message)
+ {
+ var logger = GetLogger();
+ logger.Info(GetMessage(message));
+ }
+
+ ///
+ /// Log message with debug level
+ ///
+ /// Message to log
+ public static void Debug(string message)
+ {
+ var logger = GetLogger();
+ logger.Debug(GetMessage(message));
+ }
+
+ ///
+ /// Log message with warning level
+ ///
+ /// Message to log
+ public static void Warn(string message)
+ {
+ var logger = GetLogger();
+ logger.Warn(GetMessage(message));
+ }
+
+ ///
+ /// Log message with error level
+ ///
+ /// Message to log
+ public static void Error(string message)
+ {
+ var logger = GetLogger();
+ logger.Error(GetMessage(message));
+ }
}
- }
}
\ No newline at end of file
diff --git a/SharpBoss.Logging/SharpBoss.Logging.csproj b/SharpBoss.Logging/SharpBoss.Logging.csproj
index adc366a..e937358 100644
--- a/SharpBoss.Logging/SharpBoss.Logging.csproj
+++ b/SharpBoss.Logging/SharpBoss.Logging.csproj
@@ -1,7 +1,11 @@
- netcoreapp3.1
+ net48
+
+
+
+ x64
diff --git a/SharpBoss.Tests/SharpBoss.Tests.csproj b/SharpBoss.Tests/SharpBoss.Tests.csproj
index b0b298a..a6d311b 100644
--- a/SharpBoss.Tests/SharpBoss.Tests.csproj
+++ b/SharpBoss.Tests/SharpBoss.Tests.csproj
@@ -1,11 +1,15 @@
- netcoreapp3.1
+ net48
false
+
+ x64
+
+
diff --git a/SharpBoss/Models/RestRequest.cs b/SharpBoss/Models/RestRequest.cs
index 76de951..536113e 100644
--- a/SharpBoss/Models/RestRequest.cs
+++ b/SharpBoss/Models/RestRequest.cs
@@ -1,4 +1,5 @@
-using System;
+using EmbedIO;
+using System;
using System.Collections.Specialized;
using System.IO;
using System.Net;
@@ -131,6 +132,40 @@ public class RestRequest {
///
public Uri UrlReferrer { get { return this._urlReferrer; } }
+ public RestRequest(IHttpContext context)
+ {
+ this._userAgent = context.Request.UserAgent; // request.UserAgent;
+ this._userHostAddress = context.Request.RemoteEndPoint.Address.ToString();
+ this._userHostName = context.Request.RemoteEndPoint.Address.ToString();
+ //this._userLanguages = context.Request.UserLanguages;
+ this._url = context.Request.Url;
+ this._urlReferrer = context.Request.UrlReferrer;
+ //this._acceptTypes = context.Request.AcceptTypes;
+ this._contentEncoding = context.Request.ContentEncoding;
+ this._contentLength = context.Request.ContentLength64;
+ this._contentType = context.Request.ContentType;
+ //this._cookies = context.Request.Cookies;
+ this._httpMethod = context.Request.HttpMethod;
+ this._isAuthenticated = context.Request.IsAuthenticated;
+ this._isLocal = context.Request.IsLocal;
+ this._isSecureConnection = context.Request.IsSecureConnection;
+ this._isWebSocketRequest = context.Request.IsWebSocketRequest;
+ this._keepAlive = context.Request.KeepAlive;
+ this._queryString = context.Request.QueryString;
+ this._rawUrl = context.Request.RawUrl;
+
+ if (context.Request.HasEntityBody)
+ {
+ using (var body = context.Request.InputStream)
+ {
+ using (var reader = new StreamReader(body, context.Request.ContentEncoding))
+ {
+ this._body = reader.ReadToEnd();
+ }
+ }
+ }
+ }
+
///
/// Instantiate a new request with listener
///
diff --git a/SharpBoss/Processors/RestProcessor.cs b/SharpBoss/Processors/RestProcessor.cs
index 38ab119..78e2fe7 100644
--- a/SharpBoss/Processors/RestProcessor.cs
+++ b/SharpBoss/Processors/RestProcessor.cs
@@ -4,7 +4,7 @@
using System.Net;
using System.Reflection;
using System.Text.Json;
-
+using System.Text.Json.Serialization;
using SharpBoss.Attributes;
using SharpBoss.Attributes.Methods;
using SharpBoss.Exceptions;
@@ -25,6 +25,7 @@ public class RestProcessor {
private Dictionary _proxies;
private Dictionary _exceptionHandlers;
private Dictionary _injectables;
+ private JsonSerializerOptions _serializerOptions;
///
/// Create new REST processor
@@ -34,6 +35,7 @@ public RestProcessor () {
this._proxies = new Dictionary ();
this._exceptionHandlers = new Dictionary ();
this._injectables = new Dictionary ();
+ this._serializerOptions = new JsonSerializerOptions() { WriteIndented = true };
}
///
@@ -49,6 +51,12 @@ public void Init (Assembly runningAssembly, string nameSpace) {
foreach (var type in types) {
var restAttribute = type.GetCustomAttribute (typeof (REST));
+ if (typeof(JsonConverter<>).IsAssignableFrom(type) || typeof(JsonConverter).IsAssignableFrom(type))
+ {
+ Logger.Info($"Found JsonConverter {type.Name}");
+ _serializerOptions.Converters.Add((JsonConverter)Activator.CreateInstance(type));
+ }
+
if (restAttribute != null) {
Logger.Info ("Found REST class " + type.Name);
var rest = (REST)restAttribute;
@@ -137,7 +145,7 @@ public RestResponse Process (string path, string method, RestRequest request) {
if (response is string) {
return new RestResponse ((string)response);
} else {
- return new RestResponse (JsonSerializer.Serialize (response), "application/json");
+ return new RestResponse (JsonSerializer.Serialize (response, _serializerOptions), "application/json");
}
} else {
return new RestResponse ("Not found", "text/plain", HttpStatusCode.NotFound);
diff --git a/SharpBoss/SharpBoss.cs b/SharpBoss/SharpBoss.cs
index ce282de..36753fb 100644
--- a/SharpBoss/SharpBoss.cs
+++ b/SharpBoss/SharpBoss.cs
@@ -1,9 +1,12 @@
using System;
using System.Collections.Specialized;
using System.Configuration;
+using System.IO;
using System.Net;
+using System.Security.Policy;
using System.Text;
-
+using System.Threading.Tasks;
+using EmbedIO;
using SharpBoss.Logging;
using SharpBoss.Models;
using SharpBoss.Workers;
@@ -13,14 +16,14 @@ namespace SharpBoss {
/// SharBoss main class
///
public class SharpBoss {
- HttpServer _server;
+ WebServer _wserver;
ApplicationLoader _applicationLoader;
dynamic _appSettings;
private readonly string _defaultListenUrl = @"http://localhost:8080/";
private readonly string _environmentVariable = "SHARPBOSS_URL";
private readonly string _configKey = "SHARPBOSS_URL";
-
+ private string _listenURL = "";
///
/// SharpBoss initializer, the listen URL can be defined on:
///
@@ -41,7 +44,27 @@ public SharpBoss (string listenUrl = null, dynamic appSettings = null) {
this._applicationLoader = new ApplicationLoader ();
listenUrl = listenUrl + (listenUrl.EndsWith ("/") ? "" : "/");
- this._server = new HttpServer (listenUrl, ProcessHttpCalls);
+ //this._server = new HttpServer (listenUrl, ProcessHttpCalls);
+ this._wserver = new WebServer(o => o.WithUrlPrefix(listenUrl).WithMode(HttpListenerMode.EmbedIO));
+ this._wserver.WithAction(HttpVerbs.Any, RequestHandlerCallback);
+ this._listenURL = listenUrl;
+ }
+
+ public void ForceReload() {
+ this._applicationLoader.ForceReload();
+ }
+ async Task RequestHandlerCallback(IHttpContext context)
+ {
+ var ePath = context.Request.Url.AbsolutePath.Split(
+ new char[] { '/' }, 2, StringSplitOptions.RemoveEmptyEntries
+ );
+
+ var req = new RestRequest(context);
+ RestResponse r = Process(ePath, req);
+ context.Response.StatusCode = ((int)r.StatusCode);
+ context.Response.ContentType = r.ContentType;
+ context.Response.ContentLength64 = r.Result.Length;
+ context.Response.OutputStream.Write(r.Result, 0, r.Result.Length);
}
///
@@ -60,14 +83,18 @@ private void SetAppSettings (dynamic appSettings = null) {
/// Do the trick, like a boss!
///
public void Run () {
- this._server.Run ();
+ Logger.Info("Running SharpBoss WebServer");
+ this._wserver.RunAsync();
}
///
/// If u did the trick, like a boss. So it's the end D:
///
public void Stop () {
- this._server.Stop ();
+ try
+ {
+ this._wserver.Listener.Stop();
+ } catch(Exception e) { }
}
///
@@ -75,7 +102,7 @@ public void Stop () {
///
/// Listen URL
public string GetHttpServerListenUrl () {
- return this._server.ListenUrl;
+ return this._listenURL;
}
///
@@ -89,42 +116,59 @@ RestResponse ProcessHttpCalls (HttpListenerRequest request) {
);
var req = new RestRequest (request);
+ return Process(ePath, req);
+ }
- if (ePath.Length == 0) {
- return new RestResponse ("No such endpoint.", "text/plain", HttpStatusCode.NotFound);
- } else {
+ RestResponse Process(string[] ePath, RestRequest req)
+ {
+
+ if (ePath.Length == 0)
+ {
+ return new RestResponse("No such endpoint.", "text/plain", HttpStatusCode.NotFound);
+ }
+ else
+ {
var path = ePath.Length > 1 ? "/" + ePath[1] : "/";
- var method = request.HttpMethod;
+ var method = req.HttpMethod;
var app = ePath[0];
- Logger.Debug (string.Format ("Received request for: APP={0} {1} {2}", app, method, path));
+ Logger.Debug(string.Format("Received request for: APP={0} {1} {2}", app, method, path));
- if (this._applicationLoader.ContainsEndPoint (app, path, method)) {
- try {
- return this._applicationLoader.Process (app, path, method, req);
- } catch (Exception ex) {
- var response = new RestResponse ();
+ if (this._applicationLoader.ContainsEndPoint(app, path, method))
+ {
+ try
+ {
+ return this._applicationLoader.Process(app, path, method, req);
+ }
+ catch (Exception ex)
+ {
+ var response = new RestResponse();
var exceptionMessage = "";
- if (ex.InnerException != null) {
- exceptionMessage = ex.InnerException.ToString ();
- } else {
- exceptionMessage = ex.ToString ();
+ if (ex.InnerException != null)
+ {
+ exceptionMessage = ex.InnerException.ToString();
+ }
+ else
+ {
+ exceptionMessage = ex.ToString();
}
- Logger.Error (string.Format (
+ Logger.Error(string.Format(
"Exception when calling application {0} in endpoint {1} {2}\r\n{3}",
app, method, path, exceptionMessage
));
response.StatusCode = HttpStatusCode.InternalServerError;
response.ContentType = "text/plain";
- response.Result = Encoding.UTF8.GetBytes (exceptionMessage);
+ response.Result = Encoding.UTF8.GetBytes(exceptionMessage);
return response;
}
- } else {
- return new RestResponse ("No such endpoint.", "text/plain", HttpStatusCode.NotFound);
+ }
+ else
+ {
+ return new RestResponse("No such endpoint.", "text/plain", HttpStatusCode.NotFound);
}
}
}
diff --git a/SharpBoss/SharpBoss.csproj b/SharpBoss/SharpBoss.csproj
index fbd8079..bdd9ab0 100644
--- a/SharpBoss/SharpBoss.csproj
+++ b/SharpBoss/SharpBoss.csproj
@@ -1,17 +1,24 @@
-
+
- netcoreapp3.1
+ net48
+
+
+
+ x64
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
@@ -19,10 +26,13 @@
-
+
+
+
+
diff --git a/SharpBoss/Workers/ApplicationLoader.cs b/SharpBoss/Workers/ApplicationLoader.cs
index 116e35f..167e533 100644
--- a/SharpBoss/Workers/ApplicationLoader.cs
+++ b/SharpBoss/Workers/ApplicationLoader.cs
@@ -3,343 +3,404 @@
using System.IO;
using System.Linq;
using System.Reflection;
-using System.Runtime.Loader;
+using System.Security.Policy;
using System.Timers;
using SharpBoss.Logging;
using SharpBoss.Models;
-namespace SharpBoss.Workers {
- ///
- ///
- ///
- internal class ApplicationLoader {
- Timer _timer;
-
- Dictionary _appDomains;
- Dictionary _loaderWorkers;
- Dictionary _appActions;
-
- FileSystemWatcher _watcher;
-
- string _appsDir;
- string _deployedDir;
-
- ///
- /// Start the Rest watcher
- ///
- public ApplicationLoader () {
- this._appDomains = new Dictionary ();
- this._loaderWorkers = new Dictionary ();
- this._watcher = new FileSystemWatcher ();
- this._appActions = new Dictionary ();
- this._appsDir = Path.Combine (".", "apps");
- this._deployedDir = Path.Combine (".", "deployed");
-
- this.Init ();
-
- this._timer = new Timer ();
- this._timer.Interval = 5 * 1000;
-
- this._watcher.Path = Path.Combine (".", "apps");
- Logger.Info ("Attaching FileSystemWatcher to " + this._watcher.Path);
-
- this._watcher.NotifyFilter = NotifyFilters.LastAccess
- | NotifyFilters.LastWrite
- | NotifyFilters.FileName
- | NotifyFilters.DirectoryName;
-
- this._watcher.Filter = "*.*";
- this._watcher.IncludeSubdirectories = true;
- this._watcher.EnableRaisingEvents = true;
- }
-
- ///
- /// Define all event handlers
- ///
- private void DefineEvents () {
- this._timer.Elapsed += Timer_Elapsed;
- this._watcher.Changed += new FileSystemEventHandler (onChanged);
- this._watcher.Created += new FileSystemEventHandler (onCreated);
- this._watcher.Deleted += new FileSystemEventHandler (onChanged);
- this._watcher.Renamed += new RenamedEventHandler (onRenamed);
- }
-
+namespace SharpBoss.Workers
+{
///
- /// Event triggered after start a timer to update assembly
+ ///
///
- /// Event source
- /// Event arguments
- private void Timer_Elapsed (object sender, ElapsedEventArgs e) {
- Logger.Info ("AppTimer Elapsed. Checking for application changes.");
-
- var appActions = new List ();
-
- lock (this._appActions) {
- var applicationNames = this._appActions.Keys.Select (x => x).ToArray ();
-
- foreach (var applicationName in applicationNames) {
- appActions.Add (this._appActions[applicationName]);
- this._appActions.Remove (applicationName);
+ internal class ApplicationLoader
+ {
+ Timer _timer;
+
+ Dictionary _appDomains;
+ Dictionary _loaderWorkers;
+ Dictionary _appActions;
+
+ FileSystemWatcher _watcher;
+
+ string _appsDir;
+ string _deployedDir;
+
+ ///
+ /// Start the Rest watcher
+ ///
+ public ApplicationLoader()
+ {
+ this._appDomains = new Dictionary();
+ this._loaderWorkers = new Dictionary();
+ this._watcher = new FileSystemWatcher();
+ this._appActions = new Dictionary();
+ this._appsDir = Path.Combine(".", "apps");
+ this._deployedDir = Path.Combine(".", "deployed");
+
+ this.Init();
+
+ this._timer = new Timer();
+ this._timer.Interval = 5 * 1000;
+
+ this._watcher.Path = Path.Combine(".", "apps");
+ Logger.Info("Attaching FileSystemWatcher to " + this._watcher.Path);
+
+ this._watcher.NotifyFilter = NotifyFilters.LastAccess
+ | NotifyFilters.LastWrite
+ | NotifyFilters.FileName
+ | NotifyFilters.DirectoryName;
+
+ this._watcher.Filter = "*.*";
+ this._watcher.IncludeSubdirectories = true;
+ this._watcher.EnableRaisingEvents = true;
+ DefineEvents();
}
- }
-
- Logger.Info (string.Format ("We have {0} application actions to do. Starting...", appActions.Count));
-
- lock (this._appDomains) {
- lock (this._loaderWorkers) {
- foreach (var appAction in appActions) {
- if (appAction.IsRemoved) {
- UnloadApplication (appAction.ApplicationName);
- Logger.Info (string.Format ("Application {0} removed from pool", appAction.ApplicationName));
- } else {
- Logger.Info (string.Format ("Application {0} is avaliable", appAction.ApplicationName));
- LoadApplication (appAction.ApplicationName);
+ public void ForceReload()
+ {
+ lock (this._appDomains)
+ {
+ Logger.Info("Force reloading apps...");
+ var keys = this._appDomains.Keys.ToList();
+ foreach (var app in keys)
+ {
+ LoadApplication(app); // Load also unloads first
+ }
}
- }
}
- }
-
- this._timer.AutoReset = false;
- this._timer.Enabled = false;
- }
-
- ///
- /// Create new application domain from folder with name
- ///
- /// Application Name
- /// Application path
- ///
- private AppDomain CreateApplicationDomain (string applicationName, string applicationPath) {
- Logger.Debug (
- string.Format (
- "Creating application domain for {0} from {1}", applicationName, applicationPath
- )
- );
-
- var applicationContext = new AssemblyLoadContext (applicationName, true);
- var assembly = applicationContext.LoadFromAssemblyPath (applicationPath);
-
- var appDomain = AppDomain.CurrentDomain;
- appDomain.Load (AssemblyName.GetAssemblyName (applicationPath));
-
- return appDomain;
- }
-
- ///
- /// Validate if endpoint already exists inside Application
- ///
- /// Application name
- /// Request path
- /// HTTP Method
- /// Returns true or false
- public bool ContainsEndPoint (string appName, string path, string method) {
- return this._loaderWorkers.ContainsKey (appName) &&
- this._loaderWorkers[appName].ContainsEndPoint (path, method);
- }
-
- ///
- /// Process endpoint request from loader Application
- ///
- /// Application name
- /// Request path
- /// HTTP Method
- /// Rest Request
- /// Returns a new Rest Response
- public RestResponse Process (string appName, string path, string method, RestRequest request) {
- var loaderWorker = this._loaderWorkers[appName];
-
- if (loaderWorker != null) {
- return loaderWorker.Process (path, method, request);
- }
-
- return new RestResponse ("LoaderWorker not initialized", "text/plain", System.Net.HttpStatusCode.InternalServerError);
- }
-
- ///
- /// Create new LoaderWorker from Application Domain
- ///
- /// Application Domain
- /// Returns a new instance of LoaderWorker
- private LoaderWorker CreateLoaderWorker (AppDomain appDomain) {
- var type = typeof (LoaderWorker);
- return (LoaderWorker)appDomain.CreateInstanceAndUnwrap (type.Assembly.FullName, type.FullName);
- }
-
- ///
- /// Initialize the process and load all applications from application directory
- ///
- private void Init () {
- if (!Directory.Exists (this._appsDir)) {
- Directory.CreateDirectory (this._appsDir);
- }
-
- var applications = Directory.GetDirectories (this._appsDir);
- var applicationNames = applications
- .Select (a => Path.GetFileName (a))
- .ToList ();
-
- foreach (var applicationName in applicationNames) {
- LoadApplication (applicationName);
- }
- }
-
- ///
- /// Event handler to trigger when a file is created
- ///
- /// Event source
- /// Event arguments
- private void onCreated (object source, FileSystemEventArgs e) {
- if (!e.FullPath.Equals (this._appsDir)) {
- ScheduleRefreshApplication (GetApplicationNameFromFolder (e.FullPath), false);
- }
- }
-
- ///
- /// Event handler to trigger when a file is deleted
- ///
- /// Event source
- /// Event arguments
- private void onDeleted (object source, FileSystemEventArgs e) {
- if (!e.FullPath.Equals (this._appsDir)) {
- ScheduleRefreshApplication (GetApplicationNameFromFolder (e.FullPath), true);
- }
- }
+ ///
+ /// Define all event handlers
+ ///
+ private void DefineEvents()
+ {
+ this._timer.Elapsed += Timer_Elapsed;
+ this._watcher.Changed += new FileSystemEventHandler(onChanged);
+ this._watcher.Created += new FileSystemEventHandler(onCreated);
+ this._watcher.Deleted += new FileSystemEventHandler(onChanged);
+ this._watcher.Renamed += new RenamedEventHandler(onRenamed);
+ }
- ///
- /// Event handler to trigger when a file is changed
- ///
- /// Event source
- /// Event arguments
- private void onChanged (object source, FileSystemEventArgs e) {
- if (!e.FullPath.Equals (this._appsDir)) {
- ScheduleRefreshApplication (GetApplicationNameFromFolder (e.FullPath), !(File.Exists (e.FullPath) || Directory.Exists (e.FullPath)));
- }
- }
+ ///
+ /// Event triggered after start a timer to update assembly
+ ///
+ /// Event source
+ /// Event arguments
+ private void Timer_Elapsed(object sender, ElapsedEventArgs e)
+ {
+ Logger.Info("AppTimer Elapsed. Checking for application changes.");
+
+ var appActions = new List();
+
+ lock (this._appActions)
+ {
+ var applicationNames = this._appActions.Keys.Select(x => x).ToArray();
+
+ foreach (var applicationName in applicationNames)
+ {
+ appActions.Add(this._appActions[applicationName]);
+ this._appActions.Remove(applicationName);
+ }
+ }
- ///
- /// Event handler to trigger when a file is renamed
- ///
- /// Event source
- /// Event arguments
- private void onRenamed (object source, RenamedEventArgs e) {
- ScheduleRefreshApplication (GetApplicationNameFromFolder (e.OldFullPath), true);
- ScheduleRefreshApplication (GetApplicationNameFromFolder (e.FullPath), false);
- }
+ Logger.Info(string.Format("We have {0} application actions to do. Starting...", appActions.Count));
+
+ lock (this._appDomains)
+ {
+ lock (this._loaderWorkers)
+ {
+ foreach (var appAction in appActions)
+ {
+ if (appAction.IsRemoved)
+ {
+ UnloadApplication(appAction.ApplicationName);
+ Logger.Info(string.Format("Application {0} removed from pool", appAction.ApplicationName));
+ }
+ else
+ {
+ Logger.Info(string.Format("Application {0} is avaliable", appAction.ApplicationName));
+ LoadApplication(appAction.ApplicationName);
+ }
+ }
+ }
+ }
- ///
- /// Schedule application refresh when
- ///
- ///
- ///
- private void ScheduleRefreshApplication (string applicationName, bool isRemoved) {
- Logger.Info ("Detected change for " + applicationName);
-
- lock (this._appActions) {
- if (this._appActions.ContainsKey (applicationName)) {
- this._appActions[applicationName].ApplicationName = applicationName;
- this._appActions[applicationName].IsRemoved = isRemoved;
- } else {
- this._appActions.Add (applicationName, new AppAction (applicationName, isRemoved));
+ this._timer.AutoReset = false;
+ this._timer.Enabled = false;
}
- }
-
- this._timer.Enabled = true;
- this._timer.Start ();
- }
- ///
- /// Get application name from folder
- ///
- /// Application folder
- /// Application name
- private string GetApplicationNameFromFolder (string folder) {
- if (File.Exists (folder)) {
- folder = Path.GetDirectoryName (folder);
- }
-
- return folder
- .Substring (folder.LastIndexOf ("apps" + Utils.DIRECTORY_SEPARATOR))
- .Split (Utils.DIRECTORY_SEPARATOR)[1];
- }
+ ///
+ /// Create new application domain from folder with name
+ ///
+ /// Application Name
+ /// Application path
+ ///
+ private AppDomain CreateApplicationDomain(string applicationName, string applicationPath)
+ {
+ Logger.Debug(
+ string.Format(
+ "Creating application domain for {0} from {1}", applicationName, applicationPath
+ )
+ );
+
+ // Assembly.LoadFrom(applicationPath);
+ // var applicationContext = AssemblyLoadContext.Default; // new AssemblyLoadContext (applicationName, true);
+ //var assembly = applicationContext.LoadFromAssemblyPath (applicationPath);
+
+ var appDomain = AppDomain.CurrentDomain;
+ appDomain.Load(AssemblyName.GetAssemblyName(applicationPath));
+
+ return appDomain;
+ }
- ///
- /// Unload application by name
- ///
- /// Application name
- private void UnloadApplication (string applicationName) {
- if (this._appDomains.ContainsKey (applicationName)) {
- Logger.Info ("Unloading " + applicationName);
- try {
- this._loaderWorkers.Remove (applicationName);
- AppDomain.Unload (this._appDomains[applicationName]);
- this._appDomains.Remove (applicationName);
-
- var directory = new DirectoryInfo (Path.Combine (".", "deployed", applicationName));
- directory.Delete (true);
- } catch (Exception ex) {
- Logger.Error (string.Format ("Failed unloading application {0}:\n{1}", applicationName, ex.ToString ()));
+ ///
+ /// Validate if endpoint already exists inside Application
+ ///
+ /// Application name
+ /// Request path
+ /// HTTP Method
+ /// Returns true or false
+ public bool ContainsEndPoint(string appName, string path, string method)
+ {
+ return this._loaderWorkers.ContainsKey(appName) &&
+ this._loaderWorkers[appName].ContainsEndPoint(path, method);
}
- }
- }
- ///
- /// Deploy application from name
- ///
- ///
- private void LoadApplication (string applicationName) {
- UnloadApplication (applicationName);
+ ///
+ /// Process endpoint request from loader Application
+ ///
+ /// Application name
+ /// Request path
+ /// HTTP Method
+ /// Rest Request
+ /// Returns a new Rest Response
+ public RestResponse Process(string appName, string path, string method, RestRequest request)
+ {
+ var loaderWorker = this._loaderWorkers[appName];
+
+ if (loaderWorker != null)
+ {
+ return loaderWorker.Process(path, method, request);
+ }
- Logger.Info ("Deploying application: " + applicationName);
+ return new RestResponse("LoaderWorker not initialized", "text/plain", System.Net.HttpStatusCode.InternalServerError);
+ }
- var appPath = Path.Combine (Environment.CurrentDirectory, this._appsDir, applicationName);
- var assemblies = Directory.GetFiles (appPath)
- .Where (x => x.EndsWith (".dll"))
- .ToList ();
+ ///
+ /// Create new LoaderWorker from Application Domain
+ ///
+ /// Application Domain
+ /// Returns a new instance of LoaderWorker
+ private LoaderWorker CreateLoaderWorker(AppDomain appDomain)
+ {
+ var type = typeof(LoaderWorker);
+ return (LoaderWorker)appDomain.CreateInstanceAndUnwrap(type.Assembly.FullName, type.FullName);
+ }
- LoaderWorker loaderWorker = new LoaderWorker ();
+ ///
+ /// Initialize the process and load all applications from application directory
+ ///
+ private void Init()
+ {
+ if (!Directory.Exists(this._appsDir))
+ {
+ Directory.CreateDirectory(this._appsDir);
+ }
- assemblies.ForEach (appAssembly => {
- var applicationPath = Path.Combine (appPath, Path.GetFileName (appAssembly));
- var applicationDomain = CreateApplicationDomain (applicationName, applicationPath);
- this._appDomains.Add (applicationName, applicationDomain);
+ var applications = Directory.GetDirectories(this._appsDir);
+ var applicationNames = applications
+ .Select(a => Path.GetFileName(a))
+ .ToList();
- loaderWorker = CreateLoaderWorker (applicationDomain);
+ foreach (var applicationName in applicationNames)
+ {
+ LoadApplication(applicationName);
+ }
+ }
- var targetPath = Path.Combine (this._deployedDir, applicationName);
- var targetFile = Path.Combine (targetPath, Path.GetFileName (appAssembly));
+ ///
+ /// Event handler to trigger when a file is created
+ ///
+ /// Event source
+ /// Event arguments
+ private void onCreated(object source, FileSystemEventArgs e)
+ {
+ if (!e.FullPath.Equals(this._appsDir))
+ {
+ ScheduleRefreshApplication(GetApplicationNameFromFolder(e.FullPath), false);
+ }
+ }
- var appDebugAssembly = appAssembly.Replace (".dll", Utils.DEBUG_SYMBOLS_EXTENSION);
- var targetDebugFile = Path.Combine (targetPath, Path.GetFileName (appDebugAssembly));
+ ///
+ /// Event handler to trigger when a file is deleted
+ ///
+ /// Event source
+ /// Event arguments
+ private void onDeleted(object source, FileSystemEventArgs e)
+ {
+ if (!e.FullPath.Equals(this._appsDir))
+ {
+ ScheduleRefreshApplication(GetApplicationNameFromFolder(e.FullPath), true);
+ }
+ }
- try {
- if (!Directory.Exists (targetPath)) {
- Directory.CreateDirectory (targetPath);
- }
+ ///
+ /// Event handler to trigger when a file is changed
+ ///
+ /// Event source
+ /// Event arguments
+ private void onChanged(object source, FileSystemEventArgs e)
+ {
+ if (!e.FullPath.Equals(this._appsDir))
+ {
+ ScheduleRefreshApplication(GetApplicationNameFromFolder(e.FullPath), !(File.Exists(e.FullPath) || Directory.Exists(e.FullPath)));
+ }
+ }
- if (File.Exists (targetFile)) {
- File.Delete (targetFile);
- }
+ ///
+ /// Event handler to trigger when a file is renamed
+ ///
+ /// Event source
+ /// Event arguments
+ private void onRenamed(object source, RenamedEventArgs e)
+ {
+ ScheduleRefreshApplication(GetApplicationNameFromFolder(e.OldFullPath), true);
+ ScheduleRefreshApplication(GetApplicationNameFromFolder(e.FullPath), false);
+ }
- if (File.Exists (targetDebugFile)) {
- File.Delete (targetDebugFile);
- }
+ ///
+ /// Schedule application refresh when
+ ///
+ ///
+ ///
+ private void ScheduleRefreshApplication(string applicationName, bool isRemoved)
+ {
+ Logger.Info("Detected change for " + applicationName);
+
+ lock (this._appActions)
+ {
+ if (this._appActions.ContainsKey(applicationName))
+ {
+ this._appActions[applicationName].ApplicationName = applicationName;
+ this._appActions[applicationName].IsRemoved = isRemoved;
+ }
+ else
+ {
+ this._appActions.Add(applicationName, new AppAction(applicationName, isRemoved));
+ }
+ }
- Logger.Info (string.Format ("Found {0}. Copying to {1}", appAssembly, targetFile));
- File.Copy (appAssembly, targetFile);
+ this._timer.Enabled = true;
+ this._timer.Start();
+ }
- if (File.Exists (appDebugAssembly)) {
- Logger.Info (string.Format ("Found debug file for {0} at {1}", appAssembly, appDebugAssembly));
- File.Copy (appDebugAssembly, targetDebugFile);
- }
+ ///
+ /// Get application name from folder
+ ///
+ /// Application folder
+ /// Application name
+ private string GetApplicationNameFromFolder(string folder)
+ {
+ if (File.Exists(folder))
+ {
+ folder = Path.GetDirectoryName(folder);
+ }
- loaderWorker.LoadAssembly (targetFile);
- } catch (Exception ex) {
- Logger.Error (string.Format ("Failed loading application assembly {0}:\n{1}", appAssembly, ex.ToString ()));
+ return folder
+ .Substring(folder.LastIndexOf("apps" + Utils.DIRECTORY_SEPARATOR))
+ .Split(Utils.DIRECTORY_SEPARATOR)[1];
}
- });
- this._loaderWorkers.Add (applicationName, loaderWorker);
+ ///
+ /// Unload application by name
+ ///
+ /// Application name
+ private void UnloadApplication(string applicationName)
+ {
+ if (this._appDomains.ContainsKey(applicationName))
+ {
+ Logger.Info("Unloading " + applicationName);
+ try
+ {
+ this._loaderWorkers.Remove(applicationName);
+ AppDomain.Unload(this._appDomains[applicationName]);
+ this._appDomains.Remove(applicationName);
+
+ var directory = new DirectoryInfo(Path.Combine(".", "deployed", applicationName));
+ directory.Delete(true);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(string.Format("Failed unloading application {0}:\n{1}", applicationName, ex.ToString()));
+ }
+ }
+ }
+ private AppDomain createDomain(string name, string folder)
+ {
+ AppDomainSetup domaininfo = new AppDomainSetup();
+ domaininfo.ApplicationBase = folder;
+ Evidence adevidence = AppDomain.CurrentDomain.Evidence;
+ return AppDomain.CreateDomain(name, adevidence, domaininfo);
+ }
+ ///
+ /// Deploy application from name
+ ///
+ ///
+ private void LoadApplication(string applicationName)
+ {
+ UnloadApplication(applicationName);
+
+ Logger.Info("Deploying application: " + applicationName);
+
+ var appPath = Path.Combine(Environment.CurrentDirectory, this._appsDir, applicationName);
+ var assemblies = Directory.GetFiles(appPath)
+ .Where(x => x.EndsWith(".dll"))
+ .ToList();
+ var appDomain = createDomain(applicationName, Environment.CurrentDirectory);
+ this._appDomains.Add(applicationName, appDomain);
+ LoaderWorker loaderWorker = new LoaderWorker();
+
+ assemblies.ForEach(appAssembly =>
+ {
+ string targetPath = Path.Combine(this._deployedDir, applicationName);
+ string targetFile = Path.Combine(targetPath, Path.GetFileName(appAssembly));
+ string appDebugAssembly = appAssembly.Replace(".dll", Utils.DEBUG_SYMBOLS_EXTENSION);
+ string targetDebugFile = Path.Combine(targetPath, Path.GetFileName(appDebugAssembly));
+ try
+ {
+ if (!Directory.Exists(targetPath))
+ {
+ Directory.CreateDirectory(targetPath);
+ }
+
+ if (File.Exists(targetFile))
+ {
+ File.Delete(targetFile);
+ }
+
+ if (File.Exists(targetDebugFile))
+ {
+ File.Delete(targetDebugFile);
+ }
+
+ Logger.Info(string.Format("Found {0}. Copying to {1}", appAssembly, targetFile));
+ File.Copy(appAssembly, targetFile);
+
+ if (File.Exists(appDebugAssembly))
+ {
+ Logger.Info(string.Format("Found debug file for {0} at {1}", appAssembly, appDebugAssembly));
+ File.Copy(appDebugAssembly, targetDebugFile);
+ }
+
+ loaderWorker.LoadAssembly(targetFile);
+ }
+ catch (Exception ex)
+ {
+ Logger.Error(string.Format("Failed loading application assembly {0}:\n{1}", appAssembly, ex.ToString()));
+ }
+ });
+
+ this._loaderWorkers.Add(applicationName, loaderWorker);
+ }
}
- }
}
\ No newline at end of file