#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 == "/") // { // foreach (string kek in context.Request.QueryString) // { // Debug.LogError(kek); // } // // HandleRedirect($"/blocks4u/dist/index.html?{context.Request.QueryString}", context); // return; // } 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(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