187 lines
5.7 KiB
C#
187 lines
5.7 KiB
C#
#if UNITY_EDITOR
|
|
using System;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Text;
|
|
using Blocks4u.Editor.DTO;
|
|
using Unity.Plastic.Newtonsoft.Json;
|
|
using Unity.Plastic.Newtonsoft.Json.Linq;
|
|
using UnityEngine;
|
|
|
|
namespace Blocks4u.Editor
|
|
{
|
|
public class BlocklyServer : IDisposable
|
|
{
|
|
private string _assetsPath;
|
|
public string URL { get; private set; }
|
|
private HttpListener _listener;
|
|
|
|
public string SessionToken { get; private set; }
|
|
private bool _running;
|
|
|
|
public BlocklyServer(string assetsPath, string url, string sessionToken)
|
|
{
|
|
_assetsPath = assetsPath;
|
|
URL = url;
|
|
SessionToken = sessionToken;
|
|
|
|
_listener = new HttpListener();
|
|
_listener.Prefixes.Add(url);
|
|
_listener.Start();
|
|
_running = true;
|
|
Listen();
|
|
}
|
|
|
|
private async void Listen()
|
|
{
|
|
while (_running)
|
|
{
|
|
ProcessRequest(await _listener.GetContextAsync());
|
|
}
|
|
}
|
|
|
|
private void ProcessRequest(HttpListenerContext context)
|
|
{
|
|
var request = context.Request;
|
|
var url = request.Url;
|
|
var path = url.AbsolutePath;
|
|
|
|
|
|
|
|
if (path != "/rpc")
|
|
{
|
|
HandleAsset(path, context);
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
HandleRpc(context);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
var response = context.Response;
|
|
response.StatusCode = 500;
|
|
response.OutputStream.Write(Encoding.UTF8.GetBytes(e.Message));
|
|
response.Close();
|
|
Debug.LogException(e);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HandleRpc(HttpListenerContext context)
|
|
{
|
|
var request = context.Request;
|
|
if (request.HttpMethod != "POST")
|
|
{
|
|
throw new Exception("Invalid HTTP method");
|
|
}
|
|
|
|
var headers = request.Headers;
|
|
if (headers["X-Auth"] != SessionToken)
|
|
{
|
|
throw new Exception("Invalid session token");
|
|
}
|
|
|
|
var response = context.Response;
|
|
using var reader = new StreamReader(request.InputStream);
|
|
var invocation = JsonConvert.DeserializeObject<MethodInvocation>(reader.ReadToEnd());
|
|
var method = typeof(RPC).GetMethod(invocation.method, new[] {typeof(JArray)});
|
|
var result = method.Invoke(null, new object[] {invocation.@params});
|
|
if (result is not JToken token)
|
|
{
|
|
throw new Exception("Invalid RPC method signature. Expected public static JToken name(JArray @params)");
|
|
}
|
|
|
|
response.ContentType = "application/json";
|
|
response.StatusCode = 200;
|
|
var json = new JObject
|
|
{
|
|
["result"] = (JToken) result
|
|
};
|
|
response.OutputStream.Write(Encoding.UTF8.GetBytes(json.ToString(Formatting.Indented)));
|
|
response.Close();
|
|
}
|
|
|
|
private void HandleAsset(string path, HttpListenerContext context)
|
|
{
|
|
// if (path.StartsWith("/assets/js/") && !path.EndsWith(".js"))
|
|
// {
|
|
// path += ".js"; //handle js module import
|
|
// }
|
|
|
|
var response = context.Response;
|
|
var file = Path.Combine(_assetsPath, path.Substring(1));
|
|
|
|
if (path.Contains("..") || !path.StartsWith("/") || !File.Exists(file))
|
|
{
|
|
response.StatusCode = 404;
|
|
response.Close();
|
|
return;
|
|
}
|
|
|
|
response.StatusCode = 200;
|
|
response.ContentType = GetContentType(Path.GetExtension(file));
|
|
|
|
var fileStream = new FileStream(file, FileMode.Open, FileAccess.Read);
|
|
fileStream.CopyTo(response.OutputStream);
|
|
fileStream.Close();
|
|
response.Close();
|
|
}
|
|
|
|
private void HandleRedirect(string path, HttpListenerContext context)
|
|
{
|
|
var response = context.Response;
|
|
response.StatusCode = 302;
|
|
response.AddHeader("Location", path);
|
|
response.Close();
|
|
}
|
|
|
|
private static string GetContentType(string ext)
|
|
{
|
|
if (string.IsNullOrEmpty(ext))
|
|
{
|
|
return "application/octet-stream";
|
|
}
|
|
|
|
// Убираем точку если есть
|
|
if (ext.StartsWith("."))
|
|
{
|
|
ext = ext.Substring(1);
|
|
}
|
|
|
|
return ext.ToLower() switch
|
|
{
|
|
"html" or "htm" => "text/html",
|
|
"js" => "application/javascript",
|
|
"css" => "text/css",
|
|
"svg" => "image/svg+xml",
|
|
"png" => "image/png",
|
|
"jpeg" or "jpg" => "image/jpeg",
|
|
"ico" => "image/x-icon",
|
|
"gif" => "image/gif",
|
|
"bmp" => "image/bmp",
|
|
"webp" => "image/webp",
|
|
"txt" => "text/plain",
|
|
"json" => "application/json",
|
|
"xml" => "application/xml",
|
|
"pdf" => "application/pdf",
|
|
"zip" => "application/zip",
|
|
"mp3" => "audio/mpeg",
|
|
"mp4" => "video/mp4",
|
|
"woff" => "font/woff",
|
|
"woff2" => "font/woff2",
|
|
"ttf" => "font/ttf",
|
|
"otf" => "font/otf",
|
|
_ => "application/octet-stream"
|
|
};
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_running = false;
|
|
_listener?.Stop();
|
|
}
|
|
}
|
|
}
|
|
#endif |