TellmePdmsPluging/Network/HttpServer.cs
2026-03-08 20:45:18 +08:00

760 lines
29 KiB
C#
Raw Permalink 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.Net;
using System.Text;
using System.IO;
using System.Collections.Generic;
using System.Web.Script.Serialization;
using TellmePdmsPluging.Commands;
using TellmePdmsPluging.Core;
using TellmePdmsPluging.Models;
namespace TellmePdmsPluging.Network
{
public class HttpServer : IDisposable
{
private readonly HttpListener _listener;
private readonly BatchTaskResultCallbackService _batchCallbackService;
private readonly int _port;
private bool _isRunning;
public HttpServer(int port = 9001)
{
_port = port;
_listener = new HttpListener();
_listener.Prefixes.Add($"http://localhost:{port}/");
_batchCallbackService = new BatchTaskResultCallbackService(
Environment.GetEnvironmentVariable("TELLME_BATCH_CALLBACK_SERVER"),
Environment.GetEnvironmentVariable("TELLME_BATCH_CALLBACK_TOKEN"),
"pdms");
}
public void Start()
{
try
{
_listener.Start();
_isRunning = true;
// 开始异步监听请求
_listener.BeginGetContext(OnHttpRequest, null);
LogMessage($"HTTP服务器已启动监听端口: {_port}");
}
catch (Exception ex)
{
LogMessage($"HTTP服务器启动失败: {ex.Message}");
throw;
}
}
public void Stop()
{
try
{
_isRunning = false;
_listener?.Stop();
LogMessage("HTTP服务器已停止");
}
catch (Exception ex)
{
LogMessage($"HTTP服务器停止时出错: {ex.Message}");
}
}
private void OnHttpRequest(IAsyncResult result)
{
if (!_isRunning) return;
try
{
var context = _listener.EndGetContext(result);
// 继续监听下一个请求
_listener.BeginGetContext(OnHttpRequest, null);
// 处理当前请求
ProcessRequest(context);
}
catch (Exception ex)
{
LogMessage($"处理HTTP请求时出错: {ex.Message}");
// 如果服务器仍在运行,继续监听
if (_isRunning)
{
try
{
_listener.BeginGetContext(OnHttpRequest, null);
}
catch { }
}
}
}
private void ProcessRequest(HttpListenerContext context)
{
try
{
var request = context.Request;
var response = context.Response;
// 设置响应头
response.ContentType = "application/json; charset=utf-8";
response.Headers.Add("Access-Control-Allow-Origin", "*");
response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
response.Headers.Add("Access-Control-Allow-Headers", "Content-Type");
string responseJson;
// 处理OPTIONS预检请求
if (request.HttpMethod == "OPTIONS")
{
response.StatusCode = 200;
response.Close();
return;
}
// 路由处理
string path = request.Url.AbsolutePath.ToLower();
switch (path)
{
case "/health":
responseJson = HandleHealthCheck();
break;
case "/test":
responseJson = HandleTest();
break;
case "/api/status/model":
responseJson = HandleModelStatus();
break;
case "/api/project/open":
responseJson = HandleProjectOpen(request);
break;
case "/api/project/close":
responseJson = HandleProjectClose(request);
break;
case "/api/mdb/open":
responseJson = HandleMdbOpen(request);
break;
case "/api/model/simplify":
responseJson = HandleModelSimplify(request);
break;
case "/api/model/shrinkwrap":
responseJson = HandleModelShrinkwrap(request);
break;
case "/api/export/ifc":
responseJson = HandleExportIfc(request);
break;
default:
response.StatusCode = 404;
responseJson = CreateErrorResponse(404, "接口不存在");
break;
}
// 发送响应
byte[] buffer = Encoding.UTF8.GetBytes(responseJson);
response.ContentLength64 = buffer.Length;
response.OutputStream.Write(buffer, 0, buffer.Length);
response.Close();
LogMessage($"{request.HttpMethod} {path} - {response.StatusCode}");
}
catch (Exception ex)
{
LogMessage($"处理请求时出错: {ex.Message}");
try
{
context.Response.StatusCode = 500;
string errorJson = CreateErrorResponse(500, "服务器内部错误");
byte[] errorBuffer = Encoding.UTF8.GetBytes(errorJson);
context.Response.OutputStream.Write(errorBuffer, 0, errorBuffer.Length);
context.Response.Close();
}
catch { }
}
}
private string HandleHealthCheck()
{
try
{
var healthData = new
{
status = "OK",
timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
memoryMB = GC.GetTotalMemory(false) / 1024 / 1024
};
return CreateSuccessResponse(healthData);
}
catch (Exception ex)
{
return CreateErrorResponse(500, $"健康检查失败: {ex.Message}");
}
}
private string HandleTest()
{
try
{
// 检查PDMS应用程序状态
bool pdmsRunning = CheckPdmsStatus();
var testData = new
{
running = pdmsRunning,
message = pdmsRunning ? "TellmePdms 与 PDMS 连接正常" : "PDMS 未运行或连接异常"
};
// 使用新的响应格式
return CreateTestResponse(true, testData, null);
}
catch (Exception ex)
{
return CreateTestResponse(false, null, ex.Message);
}
}
private string HandleModelStatus()
{
try
{
var modelStatus = PdmsManager.Instance.GetModelStatus();
if (!modelStatus.ModelLoaded)
{
return CreateErrorResponse(1001, "PDMS模型未加载");
}
return CreateSuccessResponse(modelStatus);
}
catch (Exception ex)
{
LogMessage($"获取模型状态失败: {ex.Message}");
return CreateErrorResponse(500, $"获取模型状态失败: {ex.Message}");
}
}
private string HandleModelSimplify(HttpListenerRequest request)
{
string executionId = null;
try
{
var payload = ReadRequestBody(request);
if (string.IsNullOrEmpty(payload))
{
return CreateErrorResponse(400, "请求体不能为空");
}
var serializer = new JavaScriptSerializer();
var simplifyRequest = serializer.Deserialize<SimplifyModelRequest>(payload) ?? new SimplifyModelRequest();
executionId = simplifyRequest.ExecutionId;
var command = new SimplifyModelCommand(simplifyRequest);
var invokeResult = MainThreadInvoker.Invoke(command, 600000);
if (!invokeResult.Success)
{
var msg = string.IsNullOrEmpty(invokeResult.Message) ? "模型轻量化失败" : invokeResult.Message;
NotifyBatchTaskResult(simplifyRequest.ExecutionId, false, msg, null);
return CreateErrorResponse(500, msg);
}
var result = invokeResult.Result as SimplifyModelResult;
if (result == null)
{
return CreateErrorResponse(500, "模型轻量化结果为空");
}
if (!result.Success)
{
var message = string.IsNullOrEmpty(result.Message) ? "模型轻量化失败" : result.Message;
NotifyBatchTaskResult(simplifyRequest.ExecutionId, false, message, null);
return CreateErrorResponse(500, message);
}
NotifyBatchTaskResult(simplifyRequest.ExecutionId, true, null, result);
return CreateSuccessResponse(result);
}
catch (Exception ex)
{
NotifyBatchTaskResult(executionId, false, ex.Message, null);
return CreateErrorResponse(500, $"模型轻量化失败: {ex.Message}");
}
}
private string HandleModelShrinkwrap(HttpListenerRequest request)
{
string executionId = null;
try
{
if (!string.Equals(request.HttpMethod, "POST", StringComparison.OrdinalIgnoreCase))
{
return CreateErrorResponse(405, "仅支持POST");
}
var payload = ReadRequestBody(request);
if (string.IsNullOrEmpty(payload))
{
return CreateErrorResponse(400, "请求体不能为空");
}
var serializer = new JavaScriptSerializer();
var shrinkwrapRequest = serializer.Deserialize<ShrinkwrapModelRequest>(payload) ?? new ShrinkwrapModelRequest();
executionId = shrinkwrapRequest.ExecutionId;
var command = new ShrinkwrapModelCommand(shrinkwrapRequest);
// executionId 场景采用异步提交避免长时间阻塞HTTP连接。
if (!string.IsNullOrEmpty(shrinkwrapRequest.ExecutionId))
{
MainThreadInvoker.InvokeAsync(command, asyncInvokeResult =>
{
try
{
if (!asyncInvokeResult.Success)
{
var msg = string.IsNullOrEmpty(asyncInvokeResult.Message) ? "外壳保留失败" : asyncInvokeResult.Message;
NotifyBatchTaskResult(shrinkwrapRequest.ExecutionId, false, msg, null);
return;
}
var asyncResult = asyncInvokeResult.Result as ShrinkwrapModelResult;
if (asyncResult == null)
{
NotifyBatchTaskResult(shrinkwrapRequest.ExecutionId, false, "外壳保留结果为空", null);
return;
}
if (!asyncResult.Success)
{
var message = string.IsNullOrEmpty(asyncResult.Message) ? "外壳保留失败" : asyncResult.Message;
NotifyBatchTaskResult(shrinkwrapRequest.ExecutionId, false, message, null);
return;
}
NotifyBatchTaskResult(shrinkwrapRequest.ExecutionId, true, null, asyncResult);
}
catch (Exception callbackEx)
{
NotifyBatchTaskResult(shrinkwrapRequest.ExecutionId, false, callbackEx.Message, null);
}
});
var acceptedData = new
{
accepted = true,
executionId = shrinkwrapRequest.ExecutionId,
status = "QUEUED",
message = "外壳保留任务已提交"
};
return CreateSuccessResponse(acceptedData);
}
var invokeResult = MainThreadInvoker.Invoke(command, 600000);
if (!invokeResult.Success)
{
var msg = string.IsNullOrEmpty(invokeResult.Message) ? "外壳保留失败" : invokeResult.Message;
NotifyBatchTaskResult(shrinkwrapRequest.ExecutionId, false, msg, null);
return CreateErrorResponse(500, msg);
}
var result = invokeResult.Result as ShrinkwrapModelResult;
if (result == null)
{
return CreateErrorResponse(500, "外壳保留结果为空");
}
if (!result.Success)
{
var message = string.IsNullOrEmpty(result.Message) ? "外壳保留失败" : result.Message;
NotifyBatchTaskResult(shrinkwrapRequest.ExecutionId, false, message, null);
return CreateErrorResponse(500, message);
}
NotifyBatchTaskResult(shrinkwrapRequest.ExecutionId, true, null, result);
return CreateSuccessResponse(result);
}
catch (Exception ex)
{
NotifyBatchTaskResult(executionId, false, ex.Message, null);
return CreateErrorResponse(500, $"外壳保留失败: {ex.Message}");
}
}
private string HandleProjectOpen(HttpListenerRequest request)
{
string executionId = null;
try
{
if (!string.Equals(request.HttpMethod, "POST", StringComparison.OrdinalIgnoreCase))
{
return CreateErrorResponse(405, "仅支持POST");
}
var payload = ReadRequestBody(request);
if (string.IsNullOrEmpty(payload))
{
return CreateErrorResponse(400, "请求体不能为空");
}
var serializer = new JavaScriptSerializer();
var openRequest = serializer.Deserialize<OpenProjectRequest>(payload) ?? new OpenProjectRequest();
executionId = openRequest.ExecutionId;
var command = new OpenProjectCommand(openRequest);
var invokeResult = MainThreadInvoker.Invoke(command, 600000);
if (!invokeResult.Success)
{
var msg = string.IsNullOrEmpty(invokeResult.Message) ? "打开项目失败" : invokeResult.Message;
NotifyBatchTaskResult(openRequest.ExecutionId, false, msg, null);
return CreateErrorResponse(500, msg);
}
var result = invokeResult.Result as OpenProjectResult;
if (result == null)
{
return CreateErrorResponse(500, "打开项目结果为空");
}
if (!result.Success)
{
var message = string.IsNullOrEmpty(result.Message) ? "打开项目失败" : result.Message;
NotifyBatchTaskResult(openRequest.ExecutionId, false, message, null);
return CreateErrorResponse(500, message);
}
NotifyBatchTaskResult(openRequest.ExecutionId, true, null, result);
return CreateSuccessResponse(result);
}
catch (Exception ex)
{
NotifyBatchTaskResult(executionId, false, ex.Message, null);
return CreateErrorResponse(500, $"打开项目失败: {ex.Message}");
}
}
private string HandleProjectClose(HttpListenerRequest request)
{
string executionId = null;
try
{
if (!string.Equals(request.HttpMethod, "POST", StringComparison.OrdinalIgnoreCase))
{
return CreateErrorResponse(405, "仅支持POST");
}
var payload = ReadRequestBody(request);
var serializer = new JavaScriptSerializer();
var closeRequest = string.IsNullOrEmpty(payload)
? new CloseProjectRequest()
: (serializer.Deserialize<CloseProjectRequest>(payload) ?? new CloseProjectRequest());
executionId = closeRequest.ExecutionId;
var command = new CloseProjectCommand(closeRequest);
var invokeResult = MainThreadInvoker.Invoke(command, 600000);
if (!invokeResult.Success)
{
var msg = string.IsNullOrEmpty(invokeResult.Message) ? "关闭项目失败" : invokeResult.Message;
NotifyBatchTaskResult(closeRequest.ExecutionId, false, msg, null);
return CreateErrorResponse(500, msg);
}
var result = invokeResult.Result as CloseProjectResult;
if (result == null)
{
return CreateErrorResponse(500, "关闭项目结果为空");
}
if (!result.Success)
{
var message = string.IsNullOrEmpty(result.Message) ? "关闭项目失败" : result.Message;
NotifyBatchTaskResult(closeRequest.ExecutionId, false, message, null);
return CreateErrorResponse(500, message);
}
NotifyBatchTaskResult(closeRequest.ExecutionId, true, null, result);
return CreateSuccessResponse(result);
}
catch (Exception ex)
{
NotifyBatchTaskResult(executionId, false, ex.Message, null);
return CreateErrorResponse(500, "关闭项目失败: " + ex.Message);
}
}
private string HandleMdbOpen(HttpListenerRequest request)
{
string executionId = null;
try
{
if (!string.Equals(request.HttpMethod, "POST", StringComparison.OrdinalIgnoreCase))
{
return CreateErrorResponse(405, "仅支持POST");
}
var payload = ReadRequestBody(request);
if (string.IsNullOrEmpty(payload))
{
return CreateErrorResponse(400, "请求体不能为空");
}
var serializer = new JavaScriptSerializer();
var openRequest = serializer.Deserialize<OpenMdbRequest>(payload) ?? new OpenMdbRequest();
executionId = openRequest.ExecutionId;
var command = new OpenMdbCommand(openRequest);
var invokeResult = MainThreadInvoker.Invoke(command, 600000);
if (!invokeResult.Success)
{
var msg = string.IsNullOrEmpty(invokeResult.Message) ? "打开MDB失败" : invokeResult.Message;
NotifyBatchTaskResult(openRequest.ExecutionId, false, msg, null);
return CreateErrorResponse(500, msg);
}
var result = invokeResult.Result as OpenMdbResult;
if (result == null)
{
return CreateErrorResponse(500, "打开MDB结果为空");
}
if (!result.Success)
{
var message = string.IsNullOrEmpty(result.Message) ? "打开MDB失败" : result.Message;
NotifyBatchTaskResult(openRequest.ExecutionId, false, message, null);
return CreateErrorResponse(500, message);
}
NotifyBatchTaskResult(openRequest.ExecutionId, true, null, result);
return CreateSuccessResponse(result);
}
catch (Exception ex)
{
NotifyBatchTaskResult(executionId, false, ex.Message, null);
return CreateErrorResponse(500, $"打开MDB失败: {ex.Message}");
}
}
private string HandleExportIfc(HttpListenerRequest request)
{
string executionId = null;
try
{
if (!string.Equals(request.HttpMethod, "POST", StringComparison.OrdinalIgnoreCase))
{
return CreateErrorResponse(405, "仅支持POST");
}
var payload = ReadRequestBody(request);
if (string.IsNullOrEmpty(payload))
{
return CreateErrorResponse(400, "请求体不能为空");
}
var serializer = new JavaScriptSerializer();
var exportRequest = serializer.Deserialize<ExportIfcRequest>(payload) ?? new ExportIfcRequest();
executionId = exportRequest.ExecutionId;
var command = new ExportIfcCommand(exportRequest);
var invokeResult = MainThreadInvoker.Invoke(command, 600000);
if (!invokeResult.Success)
{
var msg = string.IsNullOrEmpty(invokeResult.Message) ? "RVM导出失败" : invokeResult.Message;
NotifyBatchTaskResult(exportRequest.ExecutionId, false, msg, null);
return CreateErrorResponse(500, msg);
}
var result = invokeResult.Result as ExportIfcResult;
if (result == null)
{
return CreateErrorResponse(500, "RVM导出结果为空");
}
if (!result.Success)
{
var message = string.IsNullOrEmpty(result.Message) ? "RVM导出失败" : result.Message;
NotifyBatchTaskResult(exportRequest.ExecutionId, false, message, null);
return CreateErrorResponse(500, message);
}
NotifyBatchTaskResult(exportRequest.ExecutionId, true, null, result);
return CreateSuccessResponse(result);
}
catch (Exception ex)
{
NotifyBatchTaskResult(executionId, false, ex.Message, null);
return CreateErrorResponse(500, $"RVM导出失败: {ex.Message}");
}
}
private string ReadRequestBody(HttpListenerRequest request)
{
if (request == null || request.InputStream == null)
{
return string.Empty;
}
using (var reader = new StreamReader(request.InputStream, request.ContentEncoding ?? Encoding.UTF8))
{
return reader.ReadToEnd();
}
}
private bool CheckPdmsStatus()
{
try
{
// 检查是否在PDMS环境中运行
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
foreach (var assembly in loadedAssemblies)
{
if (assembly.FullName.Contains("Aveva.ApplicationFramework") ||
assembly.FullName.Contains("PMLNet"))
{
return true;
}
}
return false;
}
catch
{
return false;
}
}
private string CreateTestResponse(bool success, object data, string error)
{
// 手动构建JSON以确保格式正确
string dataJson = "null";
if (data != null)
{
dataJson = SimpleJsonSerialize(data);
}
string errorJson = error == null ? "null" : $"\"{error}\"";
return $"{{\"success\":{success.ToString().ToLower()},\"data\":{dataJson},\"error\":{errorJson}}}";
}
private string CreateSuccessResponse(object data)
{
return $"{{\"code\":0,\"message\":\"成功\",\"data\":{SimpleJsonSerialize(data)}}}";
}
private string CreateErrorResponse(int code, string message)
{
return $"{{\"code\":{code},\"message\":\"{message}\",\"data\":null}}";
}
private string SimpleJsonSerialize(object obj)
{
if (obj == null) return "null";
// 检查是否为ModelStatusResponse类型
if (obj is ModelStatusResponse)
{
return SerializeModelStatusResponse((ModelStatusResponse)obj);
}
// 检查基本类型
if (obj is string)
return $"\"{obj}\"";
if (obj is bool)
return obj.ToString().ToLower();
if (obj is DateTime)
return $"\"{((DateTime)obj).ToString("yyyy-MM-ddTHH:mm:ssZ")}\"";
if (obj.GetType().IsPrimitive)
return obj.ToString();
// 检查集合类型
if (obj is Dictionary<string, int>)
{
var dict = (Dictionary<string, int>)obj;
var dictParts = new List<string>();
foreach (var kvp in dict)
{
dictParts.Add($"\"{kvp.Key}\":{kvp.Value}");
}
return "{" + string.Join(",", dictParts.ToArray()) + "}";
}
if (obj is List<string>)
{
var list = (List<string>)obj;
var listParts = new List<string>();
foreach (var item in list)
{
listParts.Add($"\"{item}\"");
}
return "[" + string.Join(",", listParts.ToArray()) + "]";
}
if (obj is double[])
{
var array = (double[])obj;
var arrayParts = new List<string>();
foreach (var item in array)
{
arrayParts.Add(item.ToString());
}
return "[" + string.Join(",", arrayParts.ToArray()) + "]";
}
// 普通对象序列化
var properties = obj.GetType().GetProperties();
var jsonParts = new List<string>();
foreach (var prop in properties)
{
var value = prop.GetValue(obj, null);
string jsonValue = SimpleJsonSerialize(value);
jsonParts.Add($"\"{prop.Name}\":{jsonValue}");
}
return "{" + string.Join(",", jsonParts.ToArray()) + "}";
}
private string SerializeModelStatusResponse(ModelStatusResponse model)
{
var parts = new List<string>();
parts.Add($"\"ModelLoaded\":{model.ModelLoaded.ToString().ToLower()}");
parts.Add($"\"ProjectInfo\":{SimpleJsonSerialize(model.ProjectInfo)}");
parts.Add($"\"ModelStatistics\":{SimpleJsonSerialize(model.ModelStatistics)}");
parts.Add($"\"SessionInfo\":{SimpleJsonSerialize(model.SessionInfo)}");
parts.Add($"\"ExportDiagnostics\":{SimpleJsonSerialize(model.ExportDiagnostics)}");
return "{" + string.Join(",", parts.ToArray()) + "}";
}
private void NotifyBatchTaskResult(string executionId, bool success, string errorMessage, object result)
{
_batchCallbackService.NotifyTaskResultAsync(executionId, success, errorMessage, result);
}
private void LogMessage(string message)
{
try
{
string logPath = @"C:\temp\pdms_http_log.txt";
string logEntry = $"{DateTime.Now:yyyy-MM-dd HH:mm:ss} - {message}\r\n";
File.AppendAllText(logPath, logEntry);
}
catch { }
}
public void Dispose()
{
Stop();
_listener?.Close();
}
}
}