- Implement real-time IO value updates via IOValueChanged event - Add interlock toggle and real-time interlock change events - Fix ToggleLight to check return value of DIO.SetRoomLight - Add HW status display in Footer matching WinForms HWState - Implement GetHWStatus API and 250ms broadcast interval - Create HistoryPage React component for work history viewing - Add GetHistoryData API for database queries - Add date range selection, search, filter, and CSV export - Add History button in Header navigation - Add PickerMoveDialog component for manage operations - Fix DataSet column names (idx, PRNATTACH, PRNVALID, qtymax) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
597 lines
31 KiB
C#
597 lines
31 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Net.WebSockets;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Windows.Forms;
|
|
using Project.Dialog;
|
|
|
|
namespace Project.WebUI
|
|
{
|
|
public class WebSocketServer
|
|
{
|
|
private HttpListener _httpListener;
|
|
private List<WebSocket> _clients = new List<WebSocket>();
|
|
private fWebView _mainForm;
|
|
|
|
public WebSocketServer(string url, fWebView form)
|
|
{
|
|
_mainForm = form;
|
|
_httpListener = new HttpListener();
|
|
_httpListener.Prefixes.Add(url);
|
|
_httpListener.Start();
|
|
Console.WriteLine($"[WS] Listening on {url}");
|
|
Task.Run(AcceptConnections);
|
|
}
|
|
|
|
private async Task AcceptConnections()
|
|
{
|
|
while (_httpListener.IsListening)
|
|
{
|
|
try
|
|
{
|
|
var context = await _httpListener.GetContextAsync();
|
|
if (context.Request.IsWebSocketRequest)
|
|
{
|
|
ProcessRequest(context);
|
|
}
|
|
else
|
|
{
|
|
context.Response.StatusCode = 400;
|
|
context.Response.Close();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[WS] Error: {ex.Message}");
|
|
}
|
|
}
|
|
}
|
|
|
|
private System.Collections.Concurrent.ConcurrentDictionary<WebSocket, SemaphoreSlim> _socketLocks = new System.Collections.Concurrent.ConcurrentDictionary<WebSocket, SemaphoreSlim>();
|
|
|
|
private async void ProcessRequest(HttpListenerContext context)
|
|
{
|
|
WebSocketContext wsContext = null;
|
|
try
|
|
{
|
|
wsContext = await context.AcceptWebSocketAsync(subProtocol: null);
|
|
WebSocket socket = wsContext.WebSocket;
|
|
_socketLocks.TryAdd(socket, new SemaphoreSlim(1, 1));
|
|
|
|
lock (_clients) { _clients.Add(socket); }
|
|
Console.WriteLine("[WS] Client Connected");
|
|
|
|
await ReceiveLoop(socket);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[WS] Accept Error: {ex.Message}");
|
|
}
|
|
finally
|
|
{
|
|
if (wsContext != null)
|
|
{
|
|
WebSocket socket = wsContext.WebSocket;
|
|
lock (_clients) { _clients.Remove(socket); }
|
|
|
|
if (_socketLocks.TryRemove(socket, out var semaphore))
|
|
{
|
|
semaphore.Dispose();
|
|
}
|
|
socket.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task ReceiveLoop(WebSocket socket)
|
|
{
|
|
var buffer = new byte[1024 * 4];
|
|
while (socket.State == WebSocketState.Open)
|
|
{
|
|
try
|
|
{
|
|
var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
|
if (result.MessageType == WebSocketMessageType.Close)
|
|
{
|
|
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Closing", CancellationToken.None);
|
|
}
|
|
else if (result.MessageType == WebSocketMessageType.Text)
|
|
{
|
|
string msg = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
|
HandleMessage(msg, socket);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private async void HandleMessage(string msg, WebSocket socket)
|
|
{
|
|
// Simple JSON parsing (manual or Newtonsoft)
|
|
// Expected format: { "type": "...", "data": ... }
|
|
try
|
|
{
|
|
dynamic json = Newtonsoft.Json.JsonConvert.DeserializeObject(msg);
|
|
string type = json.type;
|
|
|
|
Console.WriteLine($"HandleMessage:{type}");
|
|
if (type == "GET_CONFIG")
|
|
{
|
|
// Simulate Delay for Loading Screen Test
|
|
await Task.Delay(1000);
|
|
|
|
// Send Config back
|
|
var bridge = new MachineBridge(_mainForm); // Re-use logic
|
|
string configJson = bridge.GetConfig();
|
|
var response = new { type = "CONFIG_DATA", data = Newtonsoft.Json.JsonConvert.DeserializeObject(configJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "GET_IO_LIST")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string ioJson = bridge.GetIOList();
|
|
var response = new { type = "IO_LIST_DATA", data = Newtonsoft.Json.JsonConvert.DeserializeObject(ioJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "GET_RECIPE_LIST")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string recipeJson = bridge.GetRecipeList();
|
|
var response = new { type = "RECIPE_LIST_DATA", data = Newtonsoft.Json.JsonConvert.DeserializeObject(recipeJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "SAVE_CONFIG")
|
|
{
|
|
string configJson = Newtonsoft.Json.JsonConvert.SerializeObject(json.data);
|
|
var bridge = new MachineBridge(_mainForm);
|
|
bridge.SaveConfig(configJson);
|
|
}
|
|
else if (type == "CONTROL")
|
|
{
|
|
string cmd = json.command;
|
|
_mainForm.Invoke(new Action(() => _mainForm.HandleCommand(cmd)));
|
|
}
|
|
else if (type == "MOVE")
|
|
{
|
|
string axis = json.axis;
|
|
double val = json.value;
|
|
_mainForm.Invoke(new Action(() => _mainForm.SetTargetPosition(axis, val)));
|
|
}
|
|
else if (type == "SET_IO")
|
|
{
|
|
int id = json.id;
|
|
bool state = json.state;
|
|
_mainForm.Invoke(new Action(() => _mainForm.SetOutput(id, state)));
|
|
}
|
|
else if (type == "SELECT_RECIPE")
|
|
{
|
|
string recipeId = json.recipeId;
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.SelectRecipe(recipeId);
|
|
var response = new { type = "RECIPE_SELECTED", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "COPY_RECIPE")
|
|
{
|
|
string recipeId = json.recipeId;
|
|
string newName = json.newName;
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.CopyRecipe(recipeId, newName);
|
|
var response = new { type = "RECIPE_COPIED", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "DELETE_RECIPE")
|
|
{
|
|
string recipeId = json.recipeId;
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.DeleteRecipe(recipeId);
|
|
var response = new { type = "RECIPE_DELETED", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "GET_RECIPE")
|
|
{
|
|
string recipeTitle = json.recipeTitle;
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string recipeJson = bridge.GetRecipe(recipeTitle);
|
|
var response = new { type = "RECIPE_DATA", data = Newtonsoft.Json.JsonConvert.DeserializeObject(recipeJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "SAVE_RECIPE")
|
|
{
|
|
string recipeTitle = json.recipeTitle;
|
|
string recipeData = Newtonsoft.Json.JsonConvert.SerializeObject(json.recipeData);
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.SaveRecipe(recipeTitle, recipeData);
|
|
var response = new { type = "RECIPE_SAVED", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "INITIALIZE_DEVICE")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.InitializeDevice();
|
|
var response = new { type = "DEVICE_INITIALIZED", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "GET_INITIALIZE_STATUS")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string statusJson = bridge.GetInitializeStatus();
|
|
var response = new { type = "INITIALIZE_STATUS_DATA", data = Newtonsoft.Json.JsonConvert.DeserializeObject(statusJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "GET_PROCESSED_DATA")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string dataJson = bridge.GetProcessedData();
|
|
var response = new { type = "PROCESSED_DATA", data = Newtonsoft.Json.JsonConvert.DeserializeObject(dataJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "CAMERA_CONNECT")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.CameraConnect();
|
|
var response = new { type = "CAMERA_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "CAMERA_DISCONNECT")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.CameraDisconnect();
|
|
var response = new { type = "CAMERA_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "CAMERA_GET_IMAGE")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.CameraGetImage();
|
|
var response = new { type = "CAMERA_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "CAMERA_LIVE_VIEW")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.CameraLiveView();
|
|
var response = new { type = "CAMERA_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "CAMERA_READ_TEST")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.CameraReadTest();
|
|
var response = new { type = "CAMERA_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "KEYENCE_TRIGGER_ON")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.KeyenceTriggerOn();
|
|
var response = new { type = "KEYENCE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "KEYENCE_TRIGGER_OFF")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.KeyenceTriggerOff();
|
|
var response = new { type = "KEYENCE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "KEYENCE_GET_IMAGE")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.KeyenceGetImage();
|
|
var response = new { type = "KEYENCE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "KEYENCE_SAVE_IMAGE")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.KeyenceSaveImage();
|
|
var response = new { type = "KEYENCE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "TOGGLE_LIGHT")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.ToggleLight();
|
|
var response = new { type = "LIGHT_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "EXECUTE_MANUAL_PRINT")
|
|
{
|
|
string sid = json.sid;
|
|
string venderLot = json.venderLot;
|
|
string qty = json.qty;
|
|
string mfg = json.mfg;
|
|
string rid = json.rid;
|
|
string spy = json.spy;
|
|
string partNo = json.partNo;
|
|
string printer = json.printer;
|
|
int count = json.count;
|
|
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.ExecuteManualPrint(sid, venderLot, qty, mfg, rid, spy, partNo, printer, count);
|
|
var response = new { type = "MANUAL_PRINT_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "CANCEL_JOB")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.CancelJob();
|
|
var response = new { type = "CANCEL_JOB_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "OPEN_MANAGE")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.OpenManage();
|
|
var response = new { type = "MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "CLOSE_MANAGE")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.CloseManage();
|
|
var response = new { type = "CLOSE_MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "OPEN_MANUAL")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.OpenManual();
|
|
var response = new { type = "MANUAL_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "OPEN_LOG_VIEWER")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.OpenLogViewer();
|
|
var response = new { type = "LOG_VIEWER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "OPEN_PROGRAM_FOLDER")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.OpenProgramFolder();
|
|
var response = new { type = "FOLDER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "OPEN_LOG_FOLDER")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.OpenLogFolder();
|
|
var response = new { type = "FOLDER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "OPEN_SCREENSHOT_FOLDER")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.OpenScreenshotFolder();
|
|
var response = new { type = "FOLDER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "OPEN_SAVED_DATA_FOLDER")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.OpenSavedDataFolder();
|
|
var response = new { type = "FOLDER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
// ===== PICKER MOVE HANDLERS =====
|
|
else if (type == "GET_PICKER_STATUS")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.GetPickerStatus();
|
|
var response = new { type = "PICKER_STATUS", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "PICKER_MOVE_LEFT")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.PickerMoveLeft();
|
|
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "PICKER_MOVE_LEFT_WAIT")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.PickerMoveLeftWait();
|
|
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "PICKER_MOVE_CENTER")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.PickerMoveCenter();
|
|
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "PICKER_MOVE_RIGHT_WAIT")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.PickerMoveRightWait();
|
|
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "PICKER_MOVE_RIGHT")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.PickerMoveRight();
|
|
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "PICKER_JOG_START")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string direction = json["direction"]?.ToString() ?? "";
|
|
string resultJson = bridge.PickerJogStart(direction);
|
|
var response = new { type = "PICKER_JOG_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "PICKER_JOG_STOP")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.PickerJogStop();
|
|
var response = new { type = "PICKER_JOG_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "PICKER_STOP")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.PickerStop();
|
|
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "CANCEL_VISION_VALIDATION")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string side = json["side"]?.ToString() ?? "left";
|
|
string resultJson = bridge.CancelVisionValidation(side);
|
|
var response = new { type = "VISION_CANCEL_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "PICKER_MANAGE_POSITION")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string side = json["side"]?.ToString() ?? "left";
|
|
string resultJson = bridge.PickerManagePosition(side);
|
|
var response = new { type = "PICKER_MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "PICKER_MANAGE_RETURN")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.PickerManageReturn();
|
|
var response = new { type = "PICKER_MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "PICKER_Z_HOME")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.PickerZHome();
|
|
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "PICKER_Z_ZERO")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.PickerZZero();
|
|
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "PICKER_TEST_PRINT")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string side = json["side"]?.ToString() ?? "left";
|
|
string resultJson = bridge.PickerTestPrint(side);
|
|
var response = new { type = "PICKER_PRINT_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "CAN_CLOSE_MANAGE")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.CanCloseManage();
|
|
var response = new { type = "CAN_CLOSE_MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
// ===== HISTORY DATA =====
|
|
else if (type == "GET_HISTORY_DATA")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string startDate = json["startDate"]?.ToString() ?? DateTime.Now.ToShortDateString();
|
|
string endDate = json["endDate"]?.ToString() ?? DateTime.Now.ToShortDateString();
|
|
string search = json["search"]?.ToString() ?? "";
|
|
string resultJson = bridge.GetHistoryData(startDate, endDate, search);
|
|
var response = new { type = "HISTORY_DATA_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
// ===== INTERLOCK HANDLERS =====
|
|
else if (type == "TOGGLE_INTERLOCK")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
int axisIndex = json["axisIndex"]?.ToObject<int>() ?? 0;
|
|
int lockIndex = json["lockIndex"]?.ToObject<int>() ?? 0;
|
|
string resultJson = bridge.ToggleInterlock(axisIndex, lockIndex);
|
|
var response = new { type = "TOGGLE_INTERLOCK_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
else if (type == "GET_INTERLOCK_LIST")
|
|
{
|
|
var bridge = new MachineBridge(_mainForm);
|
|
string resultJson = bridge.GetInterlockList();
|
|
var response = new { type = "INTERLOCK_LIST_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
|
|
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine($"[WS] Msg Error: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
private async Task Send(WebSocket socket, string message)
|
|
{
|
|
if (_socketLocks.TryGetValue(socket, out var semaphore))
|
|
{
|
|
await semaphore.WaitAsync();
|
|
try
|
|
{
|
|
if (socket.State == WebSocketState.Open)
|
|
{
|
|
byte[] buffer = Encoding.UTF8.GetBytes(message);
|
|
await socket.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
|
|
}
|
|
}
|
|
finally
|
|
{
|
|
semaphore.Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
public async void Broadcast(string message)
|
|
{
|
|
byte[] buffer = Encoding.UTF8.GetBytes(message);
|
|
WebSocket[] clientsCopy;
|
|
|
|
lock (_clients)
|
|
{
|
|
clientsCopy = _clients.ToArray();
|
|
}
|
|
|
|
foreach (var client in clientsCopy)
|
|
{
|
|
if (client.State == WebSocketState.Open && _socketLocks.TryGetValue(client, out var semaphore))
|
|
{
|
|
// Fire and forget, but safely
|
|
_ = Task.Run(async () =>
|
|
{
|
|
// Try to get lock immediately. If busy (sending previous frame), skip this frame to prevent lag.
|
|
if (await semaphore.WaitAsync(0))
|
|
{
|
|
try
|
|
{
|
|
if (client.State == WebSocketState.Open)
|
|
{
|
|
await client.SendAsync(new ArraySegment<byte>(buffer), WebSocketMessageType.Text, true, CancellationToken.None);
|
|
}
|
|
}
|
|
catch { /* Ignore send errors */ }
|
|
finally
|
|
{
|
|
semaphore.Release();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|