TellmePdmsPluging/Network/HttpServer.cs
sladro 8f5bcc0c98 添加模型缩减和项目打开功能的API支持
- 在HttpServer中实现了新的API端点:/api/project/open和/api/model/shrinkwrap
- 添加了ShrinkwrapModel和OpenProject命令的处理逻辑
- 在PdmsManager中实现了ShrinkwrapModel和OpenProject方法,支持相应请求的处理
- 更新了项目文件以包含新的命令和模型请求类

此更新增强了插件的功能,允许用户通过API进行模型缩减和项目打开操作。
2026-02-05 08:22:42 +08:00

555 lines
20 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.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 int _port;
private bool _isRunning;
public HttpServer(int port = 9001)
{
_port = port;
_listener = new HttpListener();
_listener.Prefixes.Add($"http://localhost:{port}/");
}
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/mdb/open":
responseJson = HandleMdbOpen(request);
break;
case "/api/model/simplify":
responseJson = HandleModelSimplify(request);
break;
case "/api/model/shrinkwrap":
responseJson = HandleModelShrinkwrap(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)
{
try
{
var payload = ReadRequestBody(request);
if (string.IsNullOrEmpty(payload))
{
return CreateErrorResponse(400, "请求体不能为空");
}
var serializer = new JavaScriptSerializer();
var simplifyRequest = serializer.Deserialize<SimplifyModelRequest>(payload) ?? new SimplifyModelRequest();
var command = new SimplifyModelCommand(simplifyRequest);
var result = command.Execute() as SimplifyModelResult;
if (result == null)
{
return CreateErrorResponse(500, "模型轻量化结果为空");
}
if (!result.Success)
{
var message = string.IsNullOrEmpty(result.Message) ? "模型轻量化失败" : result.Message;
return CreateErrorResponse(500, message);
}
return CreateSuccessResponse(result);
}
catch (Exception ex)
{
return CreateErrorResponse(500, $"模型轻量化失败: {ex.Message}");
}
}
private string HandleModelShrinkwrap(HttpListenerRequest request)
{
try
{
var payload = ReadRequestBody(request);
if (string.IsNullOrEmpty(payload))
{
return CreateErrorResponse(400, "请求体不能为空");
}
var serializer = new JavaScriptSerializer();
var shrinkwrapRequest = serializer.Deserialize<ShrinkwrapModelRequest>(payload) ?? new ShrinkwrapModelRequest();
var command = new ShrinkwrapModelCommand(shrinkwrapRequest);
var invokeResult = MainThreadInvoker.Invoke(command, 600000);
if (!invokeResult.Success)
{
var msg = string.IsNullOrEmpty(invokeResult.Message) ? "外壳保留失败" : invokeResult.Message;
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;
return CreateErrorResponse(500, message);
}
return CreateSuccessResponse(result);
}
catch (Exception ex)
{
return CreateErrorResponse(500, $"外壳保留失败: {ex.Message}");
}
}
private string HandleProjectOpen(HttpListenerRequest request)
{
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();
var command = new OpenProjectCommand(openRequest);
var invokeResult = MainThreadInvoker.Invoke(command, 600000);
if (!invokeResult.Success)
{
var msg = string.IsNullOrEmpty(invokeResult.Message) ? "打开项目失败" : invokeResult.Message;
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;
return CreateErrorResponse(500, message);
}
return CreateSuccessResponse(result);
}
catch (Exception ex)
{
return CreateErrorResponse(500, $"打开项目失败: {ex.Message}");
}
}
private string HandleMdbOpen(HttpListenerRequest request)
{
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();
var command = new OpenMdbCommand(openRequest);
var invokeResult = MainThreadInvoker.Invoke(command, 600000);
if (!invokeResult.Success)
{
var msg = string.IsNullOrEmpty(invokeResult.Message) ? "打开MDB失败" : invokeResult.Message;
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;
return CreateErrorResponse(500, message);
}
return CreateSuccessResponse(result);
}
catch (Exception ex)
{
return CreateErrorResponse(500, $"打开MDB失败: {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)}");
return "{" + string.Join(",", parts.ToArray()) + "}";
}
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();
}
}
}