Files
HDRobotics/Assets/Scripts/Model/ProgramModel.cs
2025-10-24 14:36:33 +09:00

268 lines
7.6 KiB
C#

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Palmmedia.ReportGenerator.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UdpClientLib;
using UnityEngine;
using static DirectorySyncer;
public interface IProgramModel
{
}
public class ProgramModel : IProgramModel
{
private string tcpBaseUrl;
private string udpBaseUrl;
HttpClient httpClient = new HttpClient();
private SingleUdpClient udpClientForHttp;
public UdpClientManager manager = new UdpClientManager();
private List<JobInfoDTO> allProgramsCache = new List<JobInfoDTO>();
public RobotProgram CurrentProgram { get; private set; }
private RobotData robotData;
private readonly object lockObject = new object();
private bool hasNewData;
public bool isUdpLoopRunning = false;
public ProgramModel(string hostip, int tcpPort, int udpPort)
{
tcpBaseUrl = $"http://{hostip}:{tcpPort}";
udpBaseUrl = $"http://{hostip}:{udpPort}";
udpClientForHttp = manager.AddClient("Udp-client2", hostip, udpPort);
}
public async Task InitializeAsync()
{
await LoadAllPrograms();
hasNewData = false;
isUdpLoopRunning = true;
return;
}
public bool IsNewDataAvailable()
{
lock (lockObject)
{
return hasNewData;
}
}
public RobotData GetLatestRobotData()
{
lock (lockObject)
{
hasNewData = false; // 데이터를 읽었으므로 플래그를 내림
return robotData; // (데이터 복사본을 반환하는 것이 더 안전할 수 있음)
}
}
public async Task<bool> CheckProgramExists(string jobProgramName)
{
string requestUri = $"{tcpBaseUrl}/file_manager/file_exist?pathname=project/jobs/{jobProgramName}";
HttpResponseMessage result = await httpClient.GetAsync(requestUri);
string jsonResponse = await result.Content.ReadAsStringAsync();
return jsonResponse.Equals("true");
}
public async Task<bool> CreateNewProgram(string userInputId)
{
if (string.IsNullOrEmpty(userInputId)) return false;
string newProgramId = $"{userInputId}.job";
if (await CheckProgramExists(newProgramId))
{
Debug.LogError("파일이 이미 존재합니다.");
return false;
}
else
Debug.Log($"{newProgramId} 생성");
string robotModelName;
try
{
robotModelName = await GetRobotModelNameAsync();
}
catch (Exception e)
{
Debug.LogError($"로봇 모델명을 가져오는 데 실패했습니다: {e.Message}");
return false;
}
NewJobRequestDTO newJob = new NewJobRequestDTO
{
fname = newProgramId,
model_name = robotModelName,
n_add_ax = 0
};
string jsonString = JsonConvert.SerializeObject(newJob);
HttpContent jsonPayload = new StringContent(jsonString, Encoding.UTF8, "application/json");
string requestUri = $"{tcpBaseUrl}/project/jobs/create_job";
try
{
HttpResponseMessage result = await httpClient.PostAsync(requestUri, jsonPayload);
if (result.IsSuccessStatusCode)
{
await LoadProgram(userInputId);
return true;
}
else
return false;
}
catch (Exception e)
{
Debug.LogError($"프로그램 생성 실패: {userInputId}, {e.Message}");
return false;
}
}
private async Task<string> GetRobotModelNameAsync()
{
string requestUri = $"{tcpBaseUrl}/project/rgen";
HttpResponseMessage result = await httpClient.GetAsync(requestUri);
string jsonResponse = await result.Content.ReadAsStringAsync();
JObject data = JObject.Parse(jsonResponse);
string modelName = (string)data.SelectToken("robot_model");
if (string.IsNullOrEmpty(modelName))
{
throw new Exception("로봇 상태 API 응답에서 모델명을 찾을 수 없습니다.");
}
return modelName;
}
public async Task<bool> GetRobotMotorStateAsync()
{
string requestUri = $"{tcpBaseUrl}/project/rgen";
HttpResponseMessage result = await httpClient.GetAsync(requestUri);
string jsonResponse = await result.Content.ReadAsStringAsync();
JObject data = JObject.Parse(jsonResponse);
int motorState = (int)data.SelectToken("enable_state");
if (motorState == 2 || motorState == 256)
return true;
else if (motorState == 1)
return false;
else
{
throw new Exception("로봇 상태 API 응답에서 모터 상태를 찾을 수 없습니다.");
}
}
public async Task GetTCPAsync()
{
while (isUdpLoopRunning)
{
try
{
//string requestUri = $"{udpBaseUrl}/project/robot/po_cur";
string requestUri = $"{tcpBaseUrl}/project/robot/po_cur";
HttpResponseMessage result = await httpClient.GetAsync(requestUri);
string jsonResponse = await result.Content.ReadAsStringAsync();
var tempRobotData = JsonConvert.DeserializeObject<RobotData>(jsonResponse, new JsonSerializerSettings { CheckAdditionalContent = false });
lock (lockObject)
{
robotData = tempRobotData;
hasNewData = true;
}
await Task.Delay(50);
}
catch (System.Exception e)
{
Debug.Log(e);
await Task.Delay(1000); // 에러 시 더 긴 대기
}
}
}
public async Task<bool> LoadProgram(string programId)
{
string requestUri = $"{tcpBaseUrl}/file_manager/files?pathname=project/jobs/{programId}&common";
HttpResponseMessage result = await httpClient.GetAsync(requestUri);
string rawTextContent = await result.Content.ReadAsStringAsync();
if (string.IsNullOrEmpty(rawTextContent))
{
return false;
}
CurrentProgram = new RobotProgram(programId, rawTextContent);
return true;
}
private async Task LoadAllPrograms()
{
allProgramsCache.Clear();
string jsonResponse = null;
string wrappedJson = null;
try
{
HttpResponseMessage result = await httpClient.GetAsync($"{tcpBaseUrl}/project/jobs_info");
jsonResponse = await result.Content.ReadAsStringAsync();
wrappedJson = $"{{\"jobs\":{jsonResponse}}}";
JobListWrapper wrapper = JsonUtility.FromJson<JobListWrapper>(wrappedJson);
if (wrapper != null && wrapper.jobs != null)
{
allProgramsCache = wrapper.jobs;
}
else
{
Debug.LogError("서버에서 job 목록을 파싱할 수 없습니다: " + jsonResponse);
}
}
catch (ArgumentException e)
{
Debug.LogError($"JSON 파싱 오류: {e.Message}");
}
catch (Exception e)
{
Debug.LogError($"LoadAllPrograms 알 수 없는 오류: {e.Message}");
}
}
public List<string> GetAllProgramIds()
{
List<string> ids = new List<string>();
foreach (var jobInfo in allProgramsCache)
{
ids.Add(jobInfo.fname);
}
return ids;
}
void OnDestroy()
{
isUdpLoopRunning = false;
}
}