using Opc.Ua; using Opc.Ua.Client; using System; using System.Threading.Tasks; using OpcPks.Core.Models; namespace OpcPks.Core.Services { public class OpcSessionManager { private readonly string _pkiPath = "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/Data/pki"; /// /// [수정] 하니웰 인사용: 단순히 연결만 하는 게 아니라 서버 시간을 읽으려 시도하여 /// 하니웰 본체 엔진이 인증서를 Rejected로 던지도록 유도합니다. /// public async Task SayHelloAsync(string ip) { try { // CertRequestModel은 최소 정보만 담아 전달 using (var session = await GetSessionAsync(ip, new CertRequestModel { PrimaryIpA = ip })) { if (session != null && session.Connected) { // 연결 성공 시 서버 시간 노드를 읽어 실제 통신이 가능한지 확인 var currentTime = session.ReadValue(Variables.Server_ServerStatus_CurrentTime); Console.WriteLine($"✅ [SayHello] 하니웰 연결 및 데이터 읽기 성공: {currentTime}"); await session.CloseAsync(); return true; } } return false; } catch (Exception ex) { // 여기서 에러가 나야 정상입니다. (인증서가 신뢰되지 않았을 때 하니웰이 거부하며 파일을 Rejected로 보냄) Console.WriteLine($"⚠️ [SayHello] 하니웰 거부 반응 유도 성공: {ex.Message}"); return false; } } /// /// [핵심] 크롤러 및 모든 서비스가 공통으로 사용하는 실제 세션 생성 로직 /// public async Task GetSessionAsync(string ip, CertRequestModel model) { if (string.IsNullOrEmpty(ip)) return null; string endpointUrl = $"opc.tcp://{ip}:4840"; var config = new ApplicationConfiguration() { ApplicationName = "OpcPksClient", ApplicationType = ApplicationType.Client, SecurityConfiguration = new SecurityConfiguration { ApplicationCertificate = new CertificateIdentifier { StoreType = "Directory", StorePath = $"{_pkiPath}/own" }, TrustedPeerCertificates = new CertificateTrustList { StoreType = "Directory", StorePath = $"{_pkiPath}/trusted" }, RejectedCertificateStore = new CertificateTrustList { StoreType = "Directory", StorePath = $"{_pkiPath}/rejected" }, AutoAcceptUntrustedCertificates = true }, TransportQuotas = new TransportQuotas { OperationTimeout = 10000 }, ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 10000 } }; await config.Validate(ApplicationType.Client); try { // 하니웰 보안 설정에 맞는 엔드포인트 선택 var endpointDescription = CoreClientUtils.SelectEndpoint(endpointUrl, true, 5000); var endpointConfiguration = EndpointConfiguration.Create(config); var endpoint = new ConfiguredEndpoint(null, endpointDescription, endpointConfiguration); // 세션 생성 시도: 이 과정 자체가 하니웰 본체에 대한 보안 컨택입니다. return await Session.Create( config, endpoint, false, "OpcPksSession", 10000, new UserIdentity(new AnonymousIdentityToken()), null); } catch (ServiceResultException sx) { Console.WriteLine($"[OPC_UA] 하니웰 보안 응답 코드: {sx.StatusCode}"); return null; } catch (Exception ex) { Console.WriteLine($"[OPC_UA] 세션 생성 중 오류: {ex.Message}"); return null; } } } }