TellmePdmsPluging/Network/HttpServer.cs
root 3082148d7e 实现PDMS模型状态API并移除硬编码数据
## 主要改进
- 实现 /api/status/model 接口,返回真实PDMS模型状态信息
- 使用MDB.CurrentMDB、Project.CurrentProject等AVEVA API获取真实数据
- 移除硬编码的CurrentSession、PositionInfo、PdmsSpecific等复杂结构
- 简化数据模型,只保留核心的真实数据字段

## 技术实现
- 通过DbSession获取真实的用户名、会话开始时间和持续时间
- 通过WorldMembers()获取真实的模型元素统计
- 修复DateTime类型的null合并运算符编译错误
- 清理不使用的方法和类定义

## API返回数据
现在返回的数据主要包含真实的PDMS信息:
- ModelLoaded: MDB连接状态检查
- ProjectName: 真实的设计数据库名称
- MdsName: 真实的MDB名称
- UserName: 真实的数据库会话用户
- StartTime: 真实的会话创建时间
- TotalElements: 真实的模型元素数量统计

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-01 10:36:02 +08:00

357 lines
12 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 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;
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 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();
}
}
}