using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net;
using TinaX;
namespace TinaXEditor.VFSKit.FileServer
{
///
/// File Server 文件服务器
///
public class FileServer
{
public static bool IsSupported => HttpListener.IsSupported;
public int Port { get; set; } = 8080;
public string UrlHead { get; set; } = "/files/";
public string FilesRootFolder { get; set; } = "";
public bool IsRunning => mHttp.IsListening;
//public List Prefixes = new List();
private HttpListener mHttp;
public FileServer()
{
mHttp = new HttpListener();
}
public void Run()
{
mHttp.Prefixes.Add($"http://*:{this.Port}/");
mHttp.Start();
if (UrlHead.StartsWith("/"))
UrlHead = UrlHead.Substring(1, UrlHead.Length - 1);
if (UrlHead.EndsWith("/"))
UrlHead = UrlHead.Substring(0, UrlHead.Length - 1);
UrlHead = UrlHead.ToLower();
mHttp.BeginGetContext(Result, null);
}
public void Stop()
{
mHttp.Stop();
}
private void Result(IAsyncResult result)
{
//再设置一次
mHttp?.BeginGetContext(this.Result, null);
var context = mHttp.EndGetContext(result);
var req = context.Request;
var resp = context.Response;
resp.ContentEncoding = Encoding.UTF8;
byte[] resp_bytes = null;
if (req.HttpMethod != "GET")
{
Handle403(ref resp, ref resp_bytes, $"you can not request assets by url: {req.RawUrl}\nMethod:{req.HttpMethod}");
}
else
{
string[] arr_url = req.RawUrl.Split('/');
string url_head = string.Empty;
if (req.RawUrl.StartsWith("/"))
{
if (arr_url != null && arr_url.Length >= 2)
url_head = arr_url[1].ToLower();
}
else
{
if (arr_url != null && arr_url.Length >= 1)
url_head = arr_url[0].ToLower();
}
if (!url_head.IsNullOrEmpty() && url_head == "hello")
resp_bytes = "hello".GetBytes();
else if(!url_head.IsNullOrEmpty() && url_head == UrlHead)
{
//请求文件,
//首先检查文件服务器自身指定的文件根目录是否存在
if (!Directory.Exists(FilesRootFolder))
{
Handle502(ref resp, ref resp_bytes, "File Server Internal Error: No valid folder path specified");
}
else
{
string file_path = "";
if (req.RawUrl.StartsWith("/"))
{
if (arr_url != null && arr_url.Length >= 3)
{
for(int i = 2; i < arr_url.Length; i++)
{
file_path += arr_url[i];
if(i != arr_url.Length-1)
{
file_path += "/";
}
}
}
}
else
{
if (arr_url != null && arr_url.Length >= 2)
{
for (int i = 1; i < arr_url.Length; i++)
{
file_path += arr_url[i];
if (i != arr_url.Length-1)
{
file_path += "/";
}
}
}
}
string sys_path = Path.Combine(FilesRootFolder, file_path);
if (File.Exists(sys_path))
{
resp_bytes = File.ReadAllBytes(sys_path);
resp.ContentType = "application/octet-stream";
resp.StatusCode = 200;
}
else
{
Handle404(ref resp, ref resp_bytes, "The file you request not found: " + file_path);
}
}
}
else
{
Handle404(ref resp, ref resp_bytes, "The url you request not found: " + req.RawUrl);
}
}
try
{
using (var stream = resp.OutputStream)
{
//把处理信息返回到客户端
stream.Write(resp_bytes, 0, resp_bytes.Length);
}
}
catch (Exception ex)
{
UnityEngine.Debug.LogError("[TinaX.VFS][File Server] Response error:");
UnityEngine.Debug.LogException(ex);
}
}
private void Handle404(ref HttpListenerResponse resp,ref byte[] resp_bytes, string message)
{
resp.StatusCode = 404;
resp.ContentType = "text/plain;charset=UTF-8";
resp_bytes = Encoding.UTF8.GetBytes(message);
}
private void Handle403(ref HttpListenerResponse resp, ref byte[] resp_bytes, string message)
{
resp.StatusCode = 403;
resp.ContentType = "text/plain;charset=UTF-8";
resp_bytes = Encoding.UTF8.GetBytes(message);
}
private void Handle502(ref HttpListenerResponse resp, ref byte[] resp_bytes, string message)
{
resp.StatusCode = 502;
resp.ContentType = "text/plain;charset=UTF-8";
resp_bytes = Encoding.UTF8.GetBytes(message);
}
}
}