## 主要改进 - 实现 /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>
357 lines
12 KiB
C#
357 lines
12 KiB
C#
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();
|
||
}
|
||
}
|
||
} |