123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- using System;
- using System.Linq;
- using System.Net;
- using System.Text;
- using System.Threading;
- using System.Threading.Tasks;
- using Vinno.FIS.Sonopost.Assets;
- using Vinno.FIS.Sonopost.Features.Web;
- using Vinno.FIS.Sonopost.Settings;
- using Vinno.FIS.Sonopost.WebApi;
- using Vinno.IUS.Common.Log;
- namespace Vinno.FIS.Sonopost
- {
- internal class WebHost : IDisposable
- {
- private bool _isDisposed;
- private bool _isHttpRunning;
- private bool _isWsRunning;
- private HttpListener _httpListener;
- private HttpListener _wsListener;
- private ViewEngine _viewEngine;
- private WebApiEngine _webapiHost;
- private WebPreviewHandler _webPreviewHandler;
- public WebHost()
- {
- _viewEngine = new ViewEngine();
- _webapiHost = new WebApiEngine();
- _webPreviewHandler = new WebPreviewHandler();
- }
- ~WebHost()
- {
- DoDispose();
- }
- /// <summary>
- /// Start Http Host
- /// </summary>
- internal void Start()
- {
- StartHttp(SonopostSystemSettings.Instance.WebSetting.WebPort, SonopostSystemSettings.Instance.WebSetting.WebPortStandby);
- StartWebScocket(SonopostSystemSettings.Instance.WebSetting.WebSocketPort);
- }
- private void StartHttp(int mainPort, int standbyPort = -1)
- {
- _httpListener = new HttpListener();
- if (CheckPortInUse(mainPort))
- {
- Logger.WriteLineWarn($"[{nameof(WebHost)}]{nameof(StartHttp)}:Port {mainPort} is occupied.");
- return;
- }
- _httpListener.Prefixes.Add($"http://*:{mainPort}/");
- if (standbyPort > -1)
- {
- if (CheckPortInUse(standbyPort))
- {
- Logger.WriteLineWarn($"[{nameof(WebHost)}]{nameof(StartHttp)}:Port {standbyPort} is occupied.");
- }
- else
- {
- _httpListener.Prefixes.Add($"http://*:{standbyPort}/");
- }
- }
- try
- {
- _httpListener.Start();
- _isHttpRunning = true;
- Thread thread = new Thread(new ThreadStart(async () =>
- {
- while (_isHttpRunning)
- {
- try
- {
- HttpListenerContext context = await _httpListener.GetContextAsync();
- if (context.Request.IsWebSocketRequest)
- {
- context.Response.StatusCode = HttpStatusCode.NotFound.GetHashCode();
- context.Response.Close();
- continue;
- }
- await HandleRequest(context);
- }
- catch (Exception ex)
- {
- Logger.WriteLineError($"[{nameof(WebHost)}]{nameof(StartHttp)} handle context error:{ex}");
- }
- Thread.Sleep(1);
- }
- }));
- thread.Start();
- }
- catch (Exception ex)
- {
- Logger.WriteLineError($"[{nameof(WebHost)}]{nameof(StartHttp)} error:{ex}");
- try
- {
- _httpListener?.Stop();
- }
- catch { }
- }
- }
- private void StartWebScocket(int port)
- {
- _wsListener = new HttpListener();
- if (CheckPortInUse(port))
- {
- Logger.WriteLineWarn($"[{nameof(WebHost)}]{nameof(StartWebScocket)}:Port {port} is occupied.");
- return;
- }
- _wsListener.Prefixes.Add($"http://*:{port}/");
- try
- {
- _isWsRunning = true;
- _wsListener.Start();
- Thread thread = new Thread(new ThreadStart(async () =>
- {
- while (_isWsRunning)
- {
- try
- {
- HttpListenerContext context = await _wsListener.GetContextAsync();
- if (context.Request.IsWebSocketRequest)
- {
- _webPreviewHandler.HandleRequest(context);
- }
- else
- {
- context.Response.StatusCode = HttpStatusCode.NotFound.GetHashCode();
- context.Response.Close();
- }
- }
- catch (Exception ex)
- {
- Logger.WriteLineError($"[{nameof(WebHost)}]{nameof(StartWebScocket)} handle context error:{ex}");
- }
- Thread.Sleep(1);
- }
- }));
- thread.Start();
- }
- catch (Exception ex)
- {
- Logger.WriteLineError($"[{nameof(WebHost)}]{nameof(StartWebScocket)} error:{ex}");
- try
- {
- _wsListener?.Stop();
- }
- catch { }
- }
- }
- /// <summary>
- /// Handle Http Request
- /// </summary>
- /// <param name="context"></param>
- /// <returns></returns>
- private async Task HandleRequest(HttpListenerContext context)
- {
- context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
- //允许接受跨域身份验证和自定义头
- context.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
- context.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With, Authorization");
- if (System.Net.Http.HttpMethod.Get.Method.Equals(context.Request.HttpMethod))
- {
- await HandleGetRequest(context);
- }
- else if (System.Net.Http.HttpMethod.Post.Method.Equals(context.Request.HttpMethod))
- {
- await HandlePostRequest(context);
- }
- context.Response.Close();
- }
- /// <summary>
- /// 仅限静态资源
- /// </summary>
- /// <param name="context"></param>
- /// <returns></returns>
- private async Task HandleGetRequest(HttpListenerContext context)
- {
- try
- {
- string url = context.Request.RawUrl.ToLowerInvariant();
- #if DEBUG
- Logger.WriteLineInfo($"WebHost HandleGetRequest Url:{url}");
- #endif
- if (url.StartsWith("/download/"))
- {
- _viewEngine.HandleDownload(context);
- }
- else
- {
- byte[] buffer = _viewEngine.FindSource(url);
- if (buffer != null)
- {
- await context.Response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
- context.Response.StatusCode = HttpStatusCode.OK.GetHashCode();
- }
- else
- {
- context.Response.StatusCode = HttpStatusCode.NotFound.GetHashCode();
- }
- }
- }
- catch (Exception ex)
- {
- Logger.WriteLineError($"[{nameof(WebHost)}]{nameof(HandleGetRequest)} error:{ex}");
- context.Response.StatusCode = HttpStatusCode.InternalServerError.GetHashCode();
- }
- finally
- {
- context.Response.OutputStream.Flush();
- context.Response.OutputStream.Close();
- }
- }
- /// <summary>
- /// 仅限WebApi调用
- /// </summary>
- /// <param name="context"></param>
- /// <returns></returns>
- private async Task HandlePostRequest(HttpListenerContext context)
- {
- try
- {
- string url = context.Request.RawUrl.Split('?')[0].ToLowerInvariant();
- Logger.WriteLineInfo($"WebHost HandlePostRequest Url:{url}");
- if (url.StartsWith(WebApiEngine.ROUTE_PREFIX))
- {
- url = url.Substring(WebApiEngine.ROUTE_PREFIX.Length, url.Length - WebApiEngine.ROUTE_PREFIX.Length);
- byte[] bodyBytes = new byte[context.Request.ContentLength64];
- await context.Request.InputStream.ReadAsync(bodyBytes, 0, bodyBytes.Length);
- string requestJson = Encoding.UTF8.GetString(bodyBytes);
- string resultJson = _webapiHost.Handle(url, requestJson, context);
- if (string.IsNullOrWhiteSpace(resultJson))
- {
- context.Response.StatusCode = HttpStatusCode.NotFound.GetHashCode();
- }
- else
- {
- context.Response.ContentType = "application/json";
- context.Response.ContentEncoding = Encoding.UTF8;
- byte[] buffer = Encoding.UTF8.GetBytes(resultJson);
- await context.Response.OutputStream.WriteAsync(buffer, 0, buffer.Length);
- context.Response.StatusCode = HttpStatusCode.OK.GetHashCode();
- }
- }
- else
- {
- context.Response.StatusCode = HttpStatusCode.NotFound.GetHashCode();
- }
- }
- catch (Exception ex)
- {
- Logger.WriteLineError($"[{nameof(WebHost)}]{nameof(HandlePostRequest)} error:{ex}");
- context.Response.StatusCode = HttpStatusCode.InternalServerError.GetHashCode();
- }
- finally
- {
- context.Response.OutputStream.Flush();
- context.Response.OutputStream.Close();
- }
- }
- internal void Stop()
- {
- Logger.WriteLineError($"[{nameof(WebHost)}]Stop Invoke");
- _isWsRunning = false;
- _isHttpRunning = false;
- _wsListener = null;
- _httpListener = null;
- }
- private void DoDispose()
- {
- if (!_isDisposed)
- {
- Stop();
- _isDisposed = true;
- }
- }
- public void Dispose()
- {
- DoDispose();
- GC.SuppressFinalize(this);
- }
- /// <summary>
- /// 检测端口是否被占用
- /// </summary>
- /// <param name="port">端口号</param>
- /// <returns></returns>
- private bool CheckPortInUse(int port)
- {
- var properties = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties();
- IPEndPoint[] points = properties.GetActiveTcpListeners();
- return points?.Any(x => x.Port == port) ?? false;
- }
- }
- }
|