懒人记时 代码仓库
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

178 lines
5.9 KiB

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Web;
using System.Windows.Forms;
namespace AppTime
{
class WebServer
{
HttpListener listener;
Thread thread;
//public HttpListenerRequest Request;
//public HttpListenerResponse Response;
public string WebRootPath;
HashSet<string> defaultPage = new HashSet<string>(StringComparer.OrdinalIgnoreCase){
"index.html",
"index.htm",
"default.html",
"default.htm"
};
public void Start(int port, object controller, string webfolder = "web")
{
thread = new Thread(() =>
{
WebRootPath = webfolder = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), webfolder);
var folders = Directory.GetDirectories(webfolder, "*", SearchOption.AllDirectories);
var webroot = $@"http://localhost:{port}/";
listener = new HttpListener();
foreach (var f in folders)
{
listener.Prefixes.Add(webroot + f.Substring(webfolder.Length + 1).Replace("\\", "/") + "/");
}
listener.Prefixes.Add(webroot);
listener.Start();
while (true)
{
var ctx = listener.GetContext();
//Debug.WriteLine($"Web Request:{ctx.Request.Url}");
//ThreadPool.QueueUserWorkItem(_ => processRequest(ctx, webfolder, controller));
new Thread(() => processRequest(
ctx,
webfolder,
controller)
)
{ IsBackground = true, Name = "WebServer Process Request" }.Start();
}
})
{
Name = "WebServer",
IsBackground = true
};
thread.Start();
}
void processRequest(HttpListenerContext context, string webfolder, object controller)
{
var request = context.Request;
var file = webfolder + request.RawUrl.Replace("/", "\\");
string query = "";
var p = file.IndexOf("?");
if (p > 0)
{
query = file.Substring(p + 1);
file = file.Substring(0, p);
}
var response = context.Response;
byte[] data = null;
if (Path.GetFileName(Path.GetDirectoryName(file)).Equals("data", StringComparison.OrdinalIgnoreCase))
{
try
{
if (string.IsNullOrWhiteSpace(query))
{
using var reader = new StreamReader(request.InputStream);
query = reader.ReadToEnd();
}
var info = JObject.Parse(HttpUtility.UrlDecode(query));
var method = controller.GetType().GetMethod(Path.GetFileName(file));
var args = info.Value<JArray>("args").Cast<object>().ToArray();
var @params = method.GetParameters();
for (var i = 0; i < args.Length; i++)
{
if (args[i] is JObject jo)
{
args[i] = jo.ToObject(@params[i].ParameterType);
}
else
{
args[i] = Convert.ChangeType(args[i], @params[i].ParameterType);
}
}
var result = method.Invoke(controller, args);
if (result is byte[] bytes)
{
data = bytes;
}
else
{
data = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(result));
}
}
catch (Exception ex)
{
data = Encoding.UTF8.GetBytes($"bad request: method:{Path.GetFileName(file)} query:{query}");
}
}
else
{
if (Directory.Exists(file))
{
var def = Directory.GetFiles(file).FirstOrDefault(f => defaultPage.Contains(Path.GetFileName(f), StringComparer.OrdinalIgnoreCase));
if (def != null)
{
file = def;
}
}
if (File.Exists(file))
{
var mime = MimeMapping.GetMimeMapping(file);
response.Headers.Add("Content-type", mime);
if (mime.StartsWith("text/"))
{
response.ContentEncoding = Encoding.GetEncoding("utf-8");
data = Encoding.UTF8.GetBytes(File.ReadAllText(file, Encoding.Default));
}
else
{
data = File.ReadAllBytes(file);
}
}
}
if (data == null)
{
data = Encoding.UTF8.GetBytes($"file not found: {file}");
}
response.ContentLength64 = data.Length;
var output = response.OutputStream;
try
{
output.Write(data, 0, data.Length);
}
catch (HttpListenerException ex)
{
}
output.Close();
}
public void Stop()
{
thread.Abort();
listener.Stop();
listener.Close();
}
}
}