Files
XMen/Assets/Scripts/HttpServer.cs
2026-02-12 10:24:48 +08:00

313 lines
7.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
using UnityEngine;
using System.Threading.Tasks;
[Serializable]
public class IntentMessage
{
public string intent;
}
[Serializable]
public class PlayingStatusResponse
{
public int code;
public ServerData data;
public string message;
}
[Serializable]
public class ServerData
{
public string gameName;
public int gameTotalTime;
public int currentPlayTime;
}
public class HttpServer : MonoBehaviour
{
private HttpListener listener;
private Thread serverThread;
private volatile bool isRunning;
private const string SERVER_URL = "http://+:12345/";
// 子线程 → 主线程
private static ConcurrentQueue<NetMessage> messageQueue = new ConcurrentQueue<NetMessage>();
void Awake()
{
Task.Run(StartServer);
}
void Start()
{
}
#region HTTP Server
private void StartServer()
{
try
{
listener = new HttpListener();
listener.Prefixes.Add($"http://{GetLocalIP()}:12345/");
listener.Start();
isRunning = true;
ListenLoop();
Debug.Log($"✅ HTTP Server 启动成功:{SERVER_URL}");
}
catch (Exception e)
{
Debug.LogError("❌ HTTP Server 启动失败:" + e);
}
}
private string GetLocalIP()
{
var host = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName());
foreach (var ip in host.AddressList)
{
if (ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
return ip.ToString();
}
return "127.0.0.1";
}
private void ListenLoop()
{
while (isRunning && listener.IsListening)
{
try
{
var context = listener.GetContext();
ThreadPool.QueueUserWorkItem(ProcessRequest, context);
}
catch (HttpListenerException)
{
break;
}
catch (Exception e)
{
Debug.LogError(e);
}
}
}
private void ProcessRequest(object state)
{
var context = (HttpListenerContext)state;
var request = context.Request;
var response = context.Response;
response.AddHeader("Access-Control-Allow-Origin", "*");
response.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
response.AddHeader("Access-Control-Allow-Headers", "Content-Type");
response.ContentType = "application/json; charset=utf-8";
try
{
if (request.HttpMethod == "POST")
{
string raw;
using (var reader = new StreamReader(
request.InputStream,
request.ContentEncoding ?? Encoding.UTF8))
{
raw = reader.ReadToEnd();
}
Debug.Log($"📩 收到原始 JSON{raw}");
// 解析 intent
IntentMessage intentMsg = null;
try
{
intentMsg = JsonUtility.FromJson<IntentMessage>(raw);
}
catch (Exception e)
{
Debug.LogError("JSON 解析失败:" + e);
}
// 只处理 is_playing
if (intentMsg != null && intentMsg.intent == "is_playing")
{
var resp = new PlayingStatusResponse
{
code = 200,
data = new ServerData()
{
gameName = GetCurrentGameName(),
gameTotalTime = GetGameTotalTime(),
currentPlayTime = GetCurrentPlayTime()
},
message = "请求成功"
};
string json = JsonUtility.ToJson(resp);
byte[] data = Encoding.UTF8.GetBytes(json);
response.OutputStream.Write(data, 0, data.Length);
}
else
{
// 未知 intent
string err = "{\"code\":400,\"msg\":\"unknown intent\"}";
byte[] data = Encoding.UTF8.GetBytes(err);
response.OutputStream.Write(data, 0, data.Length);
}
response.Close();
return;
}
}
catch (Exception e)
{
Debug.LogError(e);
WriteResponse(response, 500, "error");
}
finally
{
response.Close();
}
}
private void WriteResponse(HttpListenerResponse response, int code, string msg)
{
string json = $"{{\"code\":{code},\"msg\":\"{msg}\"}}";
byte[] data = Encoding.UTF8.GetBytes(json);
response.OutputStream.Write(data, 0, data.Length);
}
#endregion
#region Unity Main Thread
void Update()
{
while (messageQueue.TryDequeue(out var msg))
{
Debug.Log($"📩 来自 [{msg.sender}] 指令 [{msg.command}]");
HandleMessage(msg);
}
}
#endregion
#region Message Logic
[Serializable]
public class NetMessage
{
public string sender;
public string command;
}
private NetMessage ParseMessage(string raw)
{
if (string.IsNullOrEmpty(raw))
return null;
try
{
raw = raw.Replace("\"", "").Trim();
var parts = raw.Split(':');
if (parts.Length != 2)
{
Debug.LogWarning($"消息格式错误:{raw}");
return null;
}
return new NetMessage
{
sender = parts[0].Trim(),
command = parts[1].Trim()
};
}
catch (Exception e)
{
Debug.LogError($"解析失败:{raw}\n{e}");
return null;
}
}
private void HandleMessage(NetMessage msg)
{
switch (msg.command)
{
case "isStart":
OnStartCommand(msg.sender);
break;
default:
Debug.LogWarning($"未知指令:{msg.command}");
break;
}
}
private void OnStartCommand(string sender)
{
Debug.Log($"🚀 Start 指令来自:{sender}");
// ✅ 在这里安全调用 Unity API
// GameManager.Ins.QuitGame();
}
private string GetCurrentGameName()
{
return GameInit.Ins.gameId.ToString(); // 或你自己的 GameManager
}
private int GetGameTotalTime()
{
return Mathf.FloorToInt(GameManager.Ins.vistAllTime); // 举例1 小时(秒)
}
private int GetCurrentPlayTime()
{
return GameManager.Ins.GetNowTime();
}
#endregion
#region Shutdown
void OnDestroy()
{
StopServer();
}
private void StopServer()
{
isRunning = false;
try
{
listener?.Stop();
listener?.Close();
}
catch { }
try
{
if (serverThread != null && serverThread.IsAlive)
serverThread.Join(300);
}
catch { }
Debug.Log("🛑 HTTP Server 已关闭");
}
#endregion
}