From 67f45ed8639d8169232fe458a922a112435c0119 Mon Sep 17 00:00:00 2001 From: mohit kumar Date: Fri, 20 Jan 2017 11:22:56 +0530 Subject: [PATCH] added class for web interface --- QuickFIXn/HttpServer.cs | 602 ++++++++++++++++++++++++++++++++++++++ QuickFIXn/QuickFix.csproj | 2 + 2 files changed, 604 insertions(+) create mode 100644 QuickFIXn/HttpServer.cs diff --git a/QuickFIXn/HttpServer.cs b/QuickFIXn/HttpServer.cs new file mode 100644 index 000000000..eabd37fad --- /dev/null +++ b/QuickFIXn/HttpServer.cs @@ -0,0 +1,602 @@ +using System; +using System.IO; +using System.Net; +using System.Text; +using System.Threading; +using System.Web; +using System.Web.UI; +using System.Web.UI.HtmlControls; +using QuickFix; + +namespace Acceptor +{ + public class HttpServer : IDisposable + { + private readonly HttpListener _httpListener; + private Thread _connectionThread; + private Boolean _running, _disposed; + private readonly SessionSettings _sessionSettings; + private StringBuilder _sbHtmlHeader; + + + public HttpServer(string prefix, SessionSettings settings) + { + if (!HttpListener.IsSupported) + { + // Requires at least a Windows XP with Service Pack 2 + throw new NotSupportedException( + "The Http Server cannot run on this operating system."); + } + + _httpListener = new HttpListener(); + _httpListener.Prefixes.Add(prefix); + _sessionSettings = settings; + } + + public void Start() + { + if (!_httpListener.IsListening) + { + _httpListener.Start(); + _running = true; + // Use a thread to listen to the Http requests + _connectionThread = new Thread(ConnectionThreadStart); + _connectionThread.Start(); + } + } + + public void Stop() + { + if (_httpListener.IsListening) + { + _running = false; + _httpListener.Stop(); + } + } + + private void ConnectionThreadStart() + { + try + { + while (_running) + { + // Grab the context and pass it to the processor methods to handle it + HttpListenerContext context = _httpListener.GetContext(); + HttpListenerRequest request = context.Request; + HttpListenerResponse response = context.Response; + string responseString; + + _sbHtmlHeader = new StringBuilder(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

"); + _sbHtmlHeader.AppendFormat(@"
[HOME] [RELOAD]

", request.Url.OriginalString); + + switch (request.Url.AbsolutePath) + { + case "/": + responseString = ProcessRoot(request); + break; + case "/session": + responseString = SessionDetails(request); + break; + case "/resetSession": + responseString = ResetSession(request); + break; + case "/resetSessions": + responseString = ResetSessions(request); + break; + case "/refreshSession": + responseString = RefreshSession(request); + break; + case "/refreshSessions": + responseString = RefreshSessions(request); + break; + case "/enableSessions": + responseString = EnableSessions(request); + break; + case "/disableSessions": + responseString = DisableSessions(request); + break; + default: + responseString = ProcessRoot(request); + break; + } + + byte[] buffer = Encoding.UTF8.GetBytes(responseString); + response.ContentLength64 = buffer.Length; + Stream output = response.OutputStream; + output.Write(buffer, 0, buffer.Length); + output.Close(); + } + } + catch (HttpListenerException) + { + Console.WriteLine("HTTP server was shut down."); + } + } + + private string DisableSessions(HttpListenerRequest request) + { + bool confirm = false; + StringBuilder sbHtmlPageBody = _sbHtmlHeader; + + if (request.QueryString["confirm"] != null) + { + if (Convert.ToInt16(request.QueryString["confirm"]) != 0) + { + confirm = true; + foreach (SessionID session in _sessionSettings.GetSessions()) + { + Session sessionDetails = Session.LookupSession(session); + sessionDetails.Logout(); + } + } + } + + if (confirm) + { + sbHtmlPageBody = new StringBuilder(); + sbHtmlPageBody.AppendFormat(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

", "/"); + sbHtmlPageBody.AppendFormat("

Sessions have been disabled

", "/"); + } + else + { + sbHtmlPageBody.Append("

Are you sure you want to disable all sessions ?

"); + sbHtmlPageBody.AppendFormat("
[YES, disable sessions] [NO, do not disable sessions]
", request.Url.OriginalString); + } + return sbHtmlPageBody.ToString(); + } + + private string EnableSessions(HttpListenerRequest request) + { + bool confirm = false; + string urlOriginalString = request.Url.OriginalString; + StringBuilder sbHtmlPageBody = _sbHtmlHeader; + + if (request.QueryString["confirm"] != null) + { + if (Convert.ToInt16(request.QueryString["confirm"]) != 0) + { + confirm = true; + foreach (SessionID session in _sessionSettings.GetSessions()) + { + Session sessionDetails = Session.LookupSession(session); + sessionDetails.Logon(); + } + } + } + + if (confirm) + { + sbHtmlPageBody = new StringBuilder(); + sbHtmlPageBody.AppendFormat(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

", "/"); + sbHtmlPageBody.AppendFormat("

Sessions have been enabled

", "/"); + } + else + { + sbHtmlPageBody.Append("

Are you sure you want to enable all sessions ?

"); + sbHtmlPageBody.AppendFormat("
[YES, enable sessions] [NO, do not enable sessions]
", urlOriginalString); + } + return sbHtmlPageBody.ToString(); + } + + private string RefreshSession(HttpListenerRequest request) + { + SessionID sessionId = new SessionID(request.QueryString["beginstring"], request.QueryString["sendercompid"], request.QueryString["targetcompid"]); + Session sessionDetails = Session.LookupSession(sessionId); + if (sessionDetails == null) throw new Exception("Session not found"); + StringBuilder sbHtmlPageBody = _sbHtmlHeader; + bool confirm = false; + string urlOriginalString = request.Url.OriginalString; + + string url = "/session?" + GetParameterList(urlOriginalString); + + if (request.QueryString["confirm"] != null) + { + if (Convert.ToInt16(request.QueryString["confirm"]) != 0) + { + confirm = true; + sessionDetails.Refresh(); + url = RemoveQueryStringByKey(urlOriginalString, "confirm"); + } + } + + if (confirm) + { + sbHtmlPageBody = new StringBuilder(); + sbHtmlPageBody.AppendFormat(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

", GetParameterList(urlOriginalString)); + sbHtmlPageBody.AppendFormat(@"
[HOME] [RELOAD]

", urlOriginalString); + sbHtmlPageBody.AppendFormat("

{1} has been refreshed

", GetParameterList(url), sessionId); + } + else + { + sbHtmlPageBody.AppendFormat("

Are you sure you want to refresh session {1}?

", url, sessionId); + sbHtmlPageBody.AppendFormat("
[YES, refresh session] [NO, do not refresh session]
", url); + } + return sbHtmlPageBody.ToString(); + } + + private string RefreshSessions(HttpListenerRequest request) + { + bool confirm = false; + string urlOriginalString = request.Url.OriginalString; + StringBuilder sbHtmlPageBody = _sbHtmlHeader; + + if (request.QueryString["confirm"] != null) + { + if (Convert.ToInt16(request.QueryString["confirm"]) != 0) + { + confirm = true; + foreach (SessionID session in _sessionSettings.GetSessions()) + { + Session sessionDetails = Session.LookupSession(session); + sessionDetails.Refresh(); + } + } + } + + if (confirm) + { + sbHtmlPageBody = new StringBuilder(); + sbHtmlPageBody.AppendFormat(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

", "/"); + sbHtmlPageBody.AppendFormat("

Sessions have been refreshed

", "/"); + } + else + { + sbHtmlPageBody.Append("

Are you sure you want to refresh all sessions ?

"); + sbHtmlPageBody.AppendFormat("
[YES, refresh sessions] [NO, do not refresh sessions]
", urlOriginalString); + } + return sbHtmlPageBody.ToString(); + } + + private string ResetSessions(HttpListenerRequest request) + { + bool confirm = false; + string urlOriginalString = request.Url.OriginalString; + StringBuilder sbHtmlPageBody = _sbHtmlHeader; + + if (request.QueryString["confirm"] != null) + { + if (Convert.ToInt16(request.QueryString["confirm"]) != 0) + { + confirm = true; + foreach (SessionID session in _sessionSettings.GetSessions()) + { + Session sessionDetails = Session.LookupSession(session); + sessionDetails.Reset("Reset from WebInterface"); + } + } + } + + if (confirm) + { + sbHtmlPageBody = new StringBuilder(); + sbHtmlPageBody.AppendFormat(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

", "/"); + sbHtmlPageBody.AppendFormat("

Sessions have been reset

", "/"); + } + else + { + sbHtmlPageBody.Append("

Are you sure you want to reset all sessions ?

"); + sbHtmlPageBody.AppendFormat("
[YES, reset sessions] [NO, do not reset sessions]
", urlOriginalString); + } + return sbHtmlPageBody.ToString(); + } + + private string ResetSession(HttpListenerRequest request) + { + SessionID sessionId = new SessionID(request.QueryString["beginstring"], request.QueryString["sendercompid"], request.QueryString["targetcompid"]); + Session sessionDetails = Session.LookupSession(sessionId); + if (sessionDetails == null) throw new Exception("Session not found"); + StringBuilder sbHtmlPageBody = _sbHtmlHeader; + + bool confirm = false; + string urlOriginalString = request.Url.OriginalString; + + string url = "/session?" + GetParameterList(urlOriginalString); + + if (request.QueryString["confirm"] != null) + { + if (Convert.ToInt16(request.QueryString["confirm"])!=0) + { + confirm = true; + sessionDetails.Reset("Reset from WebInterface"); + url = RemoveQueryStringByKey(urlOriginalString, "confirm"); + } + } + + if (confirm) + { + sbHtmlPageBody = new StringBuilder(); + sbHtmlPageBody.AppendFormat(@"
QuickFIX Engine Web Interface

QuickFIX Engine Web Interface

", GetParameterList(urlOriginalString)); + sbHtmlPageBody.AppendFormat(@"
[HOME] [RELOAD]

", urlOriginalString); + sbHtmlPageBody.AppendFormat("

{1} has been reset

",GetParameterList(url), sessionId); + } + else + { + sbHtmlPageBody.AppendFormat("

Are you sure you want to reset session {1}?

", url, sessionId); + sbHtmlPageBody.AppendFormat("
[YES, reset session] [NO, do not reset session]
", url); + } + return sbHtmlPageBody.ToString(); + } + + + private string ProcessRoot( HttpListenerRequest request) + { + HtmlTable table = new HtmlTable + { + Border = 1, + ID="sessionlist", + CellPadding = 2, + Width = "100%" + }; + StringBuilder sbHtmlPageBody = _sbHtmlHeader; + + //Session count + sbHtmlPageBody.AppendFormat("
{0} Sessions managed by QuickFIX

", _sessionSettings.GetSessions().Count); + + //session management links + sbHtmlPageBody.AppendFormat(@"
RESET REFRESH ENABLE DISABLE

", GetParameterList(request.Url.OriginalString)); + + HtmlTableRow row = new HtmlTableRow(); + var headerRow = new HtmlTableRow(); + headerRow.Cells.Add(new HtmlTableCell { InnerText = "Session", Align = "center" }); + headerRow.Cells.Add(new HtmlTableCell { InnerText = "Type", Align = "center" }); + headerRow.Cells.Add(new HtmlTableCell { InnerText = "Enabled", Align = "center" }); + headerRow.Cells.Add(new HtmlTableCell { InnerText = "Session Time", Align = "center" }); + headerRow.Cells.Add(new HtmlTableCell { InnerText = "Logged On", Align = "center" }); + headerRow.Cells.Add(new HtmlTableCell { InnerText = "Next Incoming", Align = "center" }); + headerRow.Cells.Add(new HtmlTableCell { InnerText = "Next Outgoing", Align = "center" }); + table.Rows.Add(headerRow); + + foreach (SessionID session in _sessionSettings.GetSessions()) + { + Session sessionDetails = Session.LookupSession(session); + row = new HtmlTableRow(); + row.Cells.Add(new HtmlTableCell { InnerHtml = String.Format("{0}:{1}->{2}", session.BeginString, session.SenderCompID, session.TargetCompID ) }); + row.Cells.Add(new HtmlTableCell { InnerHtml = sessionDetails.IsInitiator ? "initiator" : "acceptor" }); + row.Cells.Add(new HtmlTableCell { InnerHtml = sessionDetails.IsEnabled ? "yes" : "no" }); + row.Cells.Add(new HtmlTableCell { InnerHtml = sessionDetails.IsSessionTime ? "yes" : "no" }); + row.Cells.Add(new HtmlTableCell { InnerHtml = sessionDetails.IsLoggedOn ? "yes" : "no" }); + row.Cells.Add(new HtmlTableCell { InnerHtml = sessionDetails.NextTargetMsgSeqNum.ToString() }); + row.Cells.Add(new HtmlTableCell { InnerHtml = sessionDetails.NextSenderMsgSeqNum.ToString() }); + + table.Rows.Add(row); + } + + + table.Rows.Add(row); + StringWriter sr = new StringWriter(); + HtmlTextWriter hText = new HtmlTextWriter(sr); + table.RenderControl(hText); + return sbHtmlPageBody + hText.InnerWriter.ToString(); + } + + public string SessionDetails(HttpListenerRequest request) + { + SessionID sessionId = new SessionID(request.QueryString["beginstring"], request.QueryString["sendercompid"], request.QueryString["targetcompid"]); + Session sessionDetails = Session.LookupSession(sessionId); + if (sessionDetails == null) throw new Exception("Session not found"); + StringBuilder sbHtmlPageBody = _sbHtmlHeader; + + string url = request.Url.OriginalString; + string urlOriginalString = request.Url.OriginalString; + + if (request.QueryString["enabled"] != null) + { + if (!Convert.ToBoolean(request.QueryString["enabled"])) + sessionDetails.Logout(); + else + sessionDetails.Logon(); + + url = RemoveQueryStringByKey(urlOriginalString, "Enabled"); + } + + if (request.QueryString["next incoming"] != null) + { + int value = Convert.ToInt16(request.QueryString["next incoming"]); + sessionDetails.NextTargetMsgSeqNum = value <= 0 ? 1 : value; + url = RemoveQueryStringByKey(urlOriginalString, "next incoming"); + } + + if (request.QueryString["Next Outgoing"] != null) + { + int value = Convert.ToInt16(request.QueryString["Next Outgoing"]); + sessionDetails.NextSenderMsgSeqNum = value <= 0 ? 1 : value; + url = RemoveQueryStringByKey(urlOriginalString, "Next Outgoing"); + } + + if (request.QueryString["SendRedundantResendRequests"] != null) + { + sessionDetails.SendRedundantResendRequests = Convert.ToBoolean(request.QueryString["SendRedundantResendRequests"]); + url = RemoveQueryStringByKey(urlOriginalString, "SendRedundantResendRequests"); + } + + if (request.QueryString["CheckCompId"] != null) + { + sessionDetails.CheckCompID = Convert.ToBoolean(request.QueryString["CheckCompId"]); + url = RemoveQueryStringByKey(urlOriginalString, "CheckCompId"); + } + + if (request.QueryString["CheckLatency"] != null) + { + sessionDetails.CheckLatency = Convert.ToBoolean(request.QueryString["CheckLatency"]); + url = RemoveQueryStringByKey(urlOriginalString, "CheckLatency"); + } + + if (request.QueryString["MaxLatency"] != null) + { + int value = Convert.ToInt16(request.QueryString["MaxLatency"]); + sessionDetails.MaxLatency = value <= 0 ? 1 : value; + url = RemoveQueryStringByKey(urlOriginalString, "MaxLatency"); + } + + if (request.QueryString["LogonTimeout"] != null) + { + int value = Convert.ToInt16(request.QueryString["LogonTimeout"]); + sessionDetails.LogonTimeout = value <= 0 ? 1 : value; + url = RemoveQueryStringByKey(urlOriginalString, "LogonTimeout"); + } + + if (request.QueryString["LogoutTimeout"] != null) + { + int value = Convert.ToInt16(request.QueryString["LogoutTimeout"]); + sessionDetails.LogoutTimeout = value <= 0 ? 1 : value; + url = RemoveQueryStringByKey(urlOriginalString, "LogoutTimeout"); + } + + if (request.QueryString["ResetOnLogon"] != null) + { + sessionDetails.ResetOnLogon = Convert.ToBoolean(request.QueryString["ResetOnLogon"]); + url = RemoveQueryStringByKey(urlOriginalString, "ResetOnLogon"); + } + + if (request.QueryString["ResetOnLogout"] != null) + { + sessionDetails.ResetOnLogout = Convert.ToBoolean(request.QueryString["ResetOnLogout"]); + url = RemoveQueryStringByKey(urlOriginalString, "ResetOnLogout"); + } + + if (request.QueryString["ResetOnDisconnect"] != null) + { + sessionDetails.ResetOnDisconnect = Convert.ToBoolean(request.QueryString["ResetOnDisconnect"]); + url = RemoveQueryStringByKey(urlOriginalString, "ResetOnDisconnect"); + } + + if (request.QueryString["RefreshOnLogon"] != null) + { + sessionDetails.RefreshOnLogon = Convert.ToBoolean(request.QueryString["RefreshOnLogon"]); + url = RemoveQueryStringByKey(urlOriginalString, "RefreshOnLogon"); + } + + if (request.QueryString["MillisecondsInTimestamp"] != null) + { + sessionDetails.MillisecondsInTimeStamp = Convert.ToBoolean(request.QueryString["MillisecondsInTimestamp"]); + url = RemoveQueryStringByKey(urlOriginalString, "MillisecondsInTimestamp"); + } + + if (request.QueryString["PersistMessages"] != null) + { + sessionDetails.PersistMessages = Convert.ToBoolean(request.QueryString["PersistMessages"]); + url = RemoveQueryStringByKey(urlOriginalString, "PersistMessages"); + } + + + sbHtmlPageBody.AppendFormat(@"
{0}

", sessionId); + sbHtmlPageBody.AppendFormat(@"
[RESET] [REFRESH]

", GetParameterList(urlOriginalString)); + + HtmlTable table = new HtmlTable + { + Border = 1, + ID="session_details", + CellPadding = 2, + Width = "100%" + }; + table.Rows.Add(AddRow("Enabled", sessionDetails.IsEnabled, url)); + table.Rows.Add(AddRow("ConnectionType", sessionDetails.IsInitiator?"initiator": "acceptor")); + table.Rows.Add(AddRow("SessionTime", sessionDetails.IsSessionTime)); + table.Rows.Add(AddRow("LoggedOn", sessionDetails.IsLoggedOn)); + table.Rows.Add(AddRow("Next Incoming", sessionDetails.NextTargetMsgSeqNum, url)); + table.Rows.Add(AddRow("Next Outgoing", sessionDetails.NextSenderMsgSeqNum, url)); + table.Rows.Add(AddRow("SendRedundantResendRequests", sessionDetails.SendRedundantResendRequests, url)); + table.Rows.Add(AddRow("CheckCompId", sessionDetails.CheckCompID, url)); + table.Rows.Add(AddRow("CheckLatency", sessionDetails.CheckLatency, url)); + table.Rows.Add(AddRow("MaxLatency", sessionDetails.MaxLatency, url)); + table.Rows.Add(AddRow("LogonTimeout", sessionDetails.LogonTimeout, url)); + table.Rows.Add(AddRow("LogoutTimeout", sessionDetails.LogoutTimeout, url)); + table.Rows.Add(AddRow("ResetOnLogon", sessionDetails.ResetOnLogon, url)); + table.Rows.Add(AddRow("ResetOnLogout", sessionDetails.ResetOnLogout, url)); + table.Rows.Add(AddRow("ResetOnDisconnect", sessionDetails.ResetOnDisconnect, url)); + table.Rows.Add(AddRow("RefreshOnLogon", sessionDetails.RefreshOnLogon, url)); + table.Rows.Add(AddRow("MillisecondsInTimestamp", sessionDetails.MillisecondsInTimeStamp, url)); + table.Rows.Add(AddRow("PersistMessages", sessionDetails.PersistMessages, url)); + + StringWriter sr = new StringWriter(); + HtmlTextWriter hText = new HtmlTextWriter(sr); + table.RenderControl(hText); + + return sbHtmlPageBody + hText.InnerWriter.ToString(); + } + + public static string RemoveQueryStringByKey(string url, string key) + { + var uri = new Uri(url); + + // this gets all the query string key value pairs as a collection + var newQueryString = HttpUtility.ParseQueryString(uri.Query); + + // this removes the key if exists + newQueryString.Remove(key); + + // this gets the page path from root without QueryString + string pagePathWithoutQueryString = uri.GetLeftPart(UriPartial.Path); + + return newQueryString.Count > 0 + ? $"{pagePathWithoutQueryString}?{newQueryString}" + : pagePathWithoutQueryString; + } + + public static string GetParameterList(string url) + { + return HttpUtility.ParseQueryString((new Uri(url).Query)).ToString(); + } + + private static HtmlTableRow AddRow(string colName, bool value, string url="") + { + HtmlTableRow row = new HtmlTableRow(); + row.Cells.Add(new HtmlTableCell { InnerHtml = colName }); + row.Cells.Add(new HtmlTableCell { InnerHtml = value ? "yes" : "no" }); + row.Cells.Add(url.Length > 0 + ? new HtmlTableCell {InnerHtml = $"toggle"} + : new HtmlTableCell {InnerHtml = ""}); + return row; + } + + private static HtmlTableRow AddRow(string colName, int value, string url = "") + { + HtmlTableRow row = new HtmlTableRow(); + row.Cells.Add(new HtmlTableCell { InnerHtml = colName }); + row.Cells.Add(new HtmlTableCell { InnerHtml = value.ToString()}); + row.Cells.Add(new HtmlTableCell {InnerHtml = $" << " + + $" < " + + " | " + + $" > " + + $" >> " + }); + + return row; + } + private static HtmlTableRow AddRow(string colName, string value) + { + HtmlTableRow row = new HtmlTableRow(); + row.Cells.Add(new HtmlTableCell { InnerHtml = colName }); + row.Cells.Add(new HtmlTableCell { InnerHtml = value}); + row.Cells.Add(new HtmlTableCell { InnerHtml = "" }); + return row; + } + + public virtual void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + if (disposing) + { + if (_running) + { + Stop(); + } + if (_connectionThread != null) + { + _connectionThread.Abort(); + _connectionThread = null; + } + } + _disposed = true; + } + } +} diff --git a/QuickFIXn/QuickFix.csproj b/QuickFIXn/QuickFix.csproj index 69e9aa9aa..08198ea41 100644 --- a/QuickFIXn/QuickFix.csproj +++ b/QuickFIXn/QuickFix.csproj @@ -44,6 +44,7 @@ 3.5 + 3.5 @@ -54,6 +55,7 @@ +