You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
150 lines
5.2 KiB
C#
150 lines
5.2 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Timers;
|
|
using Newtonsoft.Json;
|
|
using Newtonsoft.Json.Linq;
|
|
using CncSimulator.Config;
|
|
using CncSimulator.Device;
|
|
using CncSimulator.Generator;
|
|
using CncSimulator.Core;
|
|
|
|
namespace CncSimulator.Core
|
|
{
|
|
/// <summary>单个地址的 HTTP 服务器及设备仿真集合</summary>
|
|
public class SimulatorServer
|
|
{
|
|
public AddressConfig Address { get; private set; }
|
|
public List<DeviceSimulator> Devices { get; private set; }
|
|
private readonly FanucDataGenerator _generator = new FanucDataGenerator();
|
|
private readonly LogRecorder _logRecorder = new LogRecorder();
|
|
private HttpListener _http;
|
|
private Timer _tickTimer;
|
|
public bool IsRunning { get; private set; } = false;
|
|
public int RequestCount { get; private set; } = 0;
|
|
public int TotalDeviceCount => Devices?.Count ?? 0;
|
|
public int OnlineDeviceCount => Devices?.Count(d => d.State?.IsOnline == true) ?? 0;
|
|
public DateTime StartTime { get; private set; }
|
|
|
|
public SimulatorServer(AddressConfig address, List<DeviceSimulator> devices)
|
|
{
|
|
Address = address;
|
|
Devices = devices ?? new List<DeviceSimulator>();
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
if (IsRunning) return;
|
|
_http = new HttpListener();
|
|
_http.Prefixes.Add($"http://+:{Address.Port}/");
|
|
_http.Start();
|
|
StartTime = DateTime.Now;
|
|
// 每个地址用一个定时器驱动数据变化
|
|
_tickTimer = new Timer(Address.DataChangeInterval * 1000);
|
|
_tickTimer.Elapsed += (s, e) => TickDevices();
|
|
_tickTimer.Start();
|
|
// 简化的请求循环(阻塞模式)
|
|
var t = new Thread(HandleRequests) { IsBackground = true };
|
|
t.Start();
|
|
IsRunning = true;
|
|
}
|
|
|
|
public void Stop()
|
|
{
|
|
if (!IsRunning) return;
|
|
_tickTimer?.Stop();
|
|
_http?.Close();
|
|
IsRunning = false;
|
|
}
|
|
|
|
private void TickDevices()
|
|
{
|
|
foreach (var d in Devices)
|
|
{
|
|
d.Tick();
|
|
}
|
|
}
|
|
|
|
private void HandleRequests()
|
|
{
|
|
while (_http != null && _http.IsListening)
|
|
{
|
|
try
|
|
{
|
|
var ctx = _http.GetContext();
|
|
ProcessContext(ctx);
|
|
}
|
|
catch (Exception)
|
|
{
|
|
// 忽略单次请求异常,继续监听
|
|
}
|
|
}
|
|
}
|
|
|
|
private void ProcessContext(HttpListenerContext ctx)
|
|
{
|
|
RequestCount++;
|
|
var req = ctx.Request;
|
|
var resp = ctx.Response;
|
|
resp.ContentType = "application/json";
|
|
string path = req.Url.AbsolutePath.ToLower();
|
|
if (path == "/" || path == "/data")
|
|
{
|
|
// 生成当前设备数据集合
|
|
var sw = new System.Diagnostics.Stopwatch();
|
|
sw.Start();
|
|
var list = new List<JObject>();
|
|
foreach (var d in Devices)
|
|
{
|
|
var json = _generator.GenerateDevice(d.State);
|
|
if (json != null) list.Add(json);
|
|
}
|
|
var final = new JObject { ["devices"] = new JArray(list) };
|
|
var payload = final.ToString();
|
|
sw.Stop();
|
|
_logRecorder.Record(Devices.Count, string.Join(" ", Devices.Select(v => v.State?.DeviceCode ?? "")), payload, sw.ElapsedMilliseconds);
|
|
WriteResponse(resp, payload);
|
|
}
|
|
else if (path.StartsWith("/admin"))
|
|
{
|
|
string html = "<html><body><h2>管理界面开发中</h2></body></html>";
|
|
WriteResponse(resp, html, contentType: "text/html");
|
|
}
|
|
else if (path == "/admin/api/logs")
|
|
{
|
|
var logs = _logRecorder.GetRecentLogs(50);
|
|
var arr = new JArray();
|
|
foreach (var l in logs)
|
|
{
|
|
arr.Add(new JObject
|
|
{
|
|
["timestamp"] = l.Timestamp.ToString("yyyy-MM-dd HH:mm:ss"),
|
|
["deviceCount"] = l.DeviceCount,
|
|
["keyData"] = l.KeyData,
|
|
["durationMs"] = l.DurationMs
|
|
});
|
|
}
|
|
var payload = arr.ToString();
|
|
WriteResponse(resp, payload);
|
|
}
|
|
else
|
|
{
|
|
WriteResponse(resp, "{}", contentType: "application/json");
|
|
}
|
|
resp.Close();
|
|
}
|
|
|
|
private void WriteResponse(HttpListenerResponse resp, string content, string contentType = "application/json")
|
|
{
|
|
var buffer = System.Text.Encoding.UTF8.GetBytes(content);
|
|
resp.ContentType = contentType;
|
|
resp.ContentLength64 = buffer.Length;
|
|
resp.OutputStream.Write(buffer, 0, buffer.Length);
|
|
}
|
|
}
|
|
}
|