187 lines
7.5 KiB
C#
187 lines
7.5 KiB
C#
using Microsoft.AspNetCore.Mvc;
|
|
using Npgsql;
|
|
using OpcPks.Core.Data;
|
|
using OpcPks.Core.Services;
|
|
using OpcPks.Core.Models; // CertRequestModel 참조 추가
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.IO;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace OpcPks.Web.Controllers;
|
|
|
|
[Route("Engineering")]
|
|
public class EngineeringController : Controller
|
|
{
|
|
// 하니웰 데이터 및 PKI 경로 고정
|
|
private readonly string _basePath = "/home/pacer/projects/OpcPksPlatform/OpcPks.Core/Data";
|
|
|
|
#region [기존 기능: 태그 탐사 및 관리]
|
|
|
|
[HttpGet("TagExplorer")]
|
|
public IActionResult TagExplorer() => View();
|
|
|
|
[HttpGet("Admin")]
|
|
public IActionResult Admin() => View();
|
|
|
|
[HttpPost("SearchByFilter")]
|
|
public async Task<IActionResult> SearchByFilter([FromBody] SearchRequest request)
|
|
{
|
|
var results = new List<object>();
|
|
if (request?.Suffixes == null || request.Suffixes.Count == 0) return Json(results);
|
|
|
|
using var conn = new NpgsqlConnection(DbConfig.ConnectionString);
|
|
await conn.OpenAsync();
|
|
|
|
var suffixConditions = string.Join(" OR ", request.Suffixes.Select((s, i) => $"node_id ILIKE @s{i}"));
|
|
var sql = $@"SELECT name, node_id, data_type FROM raw_node_map
|
|
WHERE name ILIKE @tagTerm AND ({suffixConditions})
|
|
ORDER BY name ASC LIMIT 1500";
|
|
|
|
using var cmd = new NpgsqlCommand(sql, conn);
|
|
cmd.Parameters.AddWithValue("tagTerm", $"%{request.TagTerm}%");
|
|
for (int i = 0; i < request.Suffixes.Count; i++)
|
|
cmd.Parameters.AddWithValue($"s{i}", $"%{request.Suffixes[i]}");
|
|
|
|
using var reader = await cmd.ExecuteReaderAsync();
|
|
while (await reader.ReadAsync()) {
|
|
results.Add(new {
|
|
name = reader.GetString(0),
|
|
nodeId = reader.GetString(1),
|
|
dataType = reader.IsDBNull(2) ? "Double" : reader.GetString(2)
|
|
});
|
|
}
|
|
return Json(results);
|
|
}
|
|
|
|
[HttpPost("RegisterTags")]
|
|
public async Task<IActionResult> RegisterTags([FromBody] List<TagRegistrationRequest> tags)
|
|
{
|
|
if (tags == null || tags.Count == 0) return Ok();
|
|
using var conn = new NpgsqlConnection(DbConfig.ConnectionString);
|
|
await conn.OpenAsync();
|
|
using var trans = await conn.BeginTransactionAsync();
|
|
try {
|
|
var masterSql = @"INSERT INTO tag_master (server_name, area_code, tag_name, parameter, full_node_id, data_type)
|
|
VALUES (@server, @area, @tag, @param, @nodeId, @type)
|
|
ON CONFLICT (full_node_id) DO UPDATE SET data_type = EXCLUDED.data_type;";
|
|
|
|
var liveSql = @"INSERT INTO tag_live_data (full_node_id, live_value, quality)
|
|
VALUES (@nodeId, '0', 'Initial')
|
|
ON CONFLICT (full_node_id) DO NOTHING;";
|
|
|
|
foreach (var tag in tags) {
|
|
string sContent = tag.NodeId.Contains("s=") ? tag.NodeId.Split("s=")[1] : tag.NodeId;
|
|
string[] parts = sContent.Split(':');
|
|
string server = parts[0];
|
|
string area = parts.Length >= 3 ? parts[1] : "unassigned";
|
|
string remains = parts.Last();
|
|
int lastDot = remains.LastIndexOf('.');
|
|
string tagName = (lastDot != -1) ? remains.Substring(0, lastDot) : remains;
|
|
string param = (lastDot != -1) ? remains.Substring(lastDot + 1) : "pv";
|
|
|
|
using (var cmd = new NpgsqlCommand(masterSql, conn, trans)) {
|
|
cmd.Parameters.AddWithValue("server", server);
|
|
cmd.Parameters.AddWithValue("area", area);
|
|
cmd.Parameters.AddWithValue("tag", tagName);
|
|
cmd.Parameters.AddWithValue("param", param);
|
|
cmd.Parameters.AddWithValue("nodeId", tag.NodeId);
|
|
cmd.Parameters.AddWithValue("type", tag.DataType ?? "Double");
|
|
await cmd.ExecuteNonQueryAsync();
|
|
}
|
|
using (var cmd = new NpgsqlCommand(liveSql, conn, trans)) {
|
|
cmd.Parameters.AddWithValue("nodeId", tag.NodeId);
|
|
await cmd.ExecuteNonQueryAsync();
|
|
}
|
|
}
|
|
await trans.CommitAsync();
|
|
return Ok();
|
|
} catch (Exception ex) {
|
|
await trans.RollbackAsync();
|
|
return BadRequest(ex.Message);
|
|
}
|
|
}
|
|
|
|
[HttpPost("RunCrawler")]
|
|
public async Task<IActionResult> RunCrawler()
|
|
{
|
|
try {
|
|
var sessionManager = new OpcSessionManager();
|
|
var session = await sessionManager.GetSessionAsync();
|
|
|
|
if (session == null || !session.Connected)
|
|
return BadRequest(new { message = "하니웰 서버 연결 실패." });
|
|
|
|
var crawler = new HoneywellCrawler(session);
|
|
string csvPath = Path.Combine(_basePath, "Honeywell_FullMap.csv");
|
|
|
|
await crawler.RunAsync("ns=1;s=$assetmodel", csvPath);
|
|
return Ok(new { message = "탐사 및 CSV 생성 완료!" });
|
|
}
|
|
catch (Exception ex) { return BadRequest(new { message = ex.Message }); }
|
|
}
|
|
|
|
[HttpPost("ImportCsv")]
|
|
public async Task<IActionResult> ImportCsv()
|
|
{
|
|
try {
|
|
using var conn = new NpgsqlConnection(DbConfig.ConnectionString);
|
|
await conn.OpenAsync();
|
|
string csvPath = Path.Combine(_basePath, "Honeywell_FullMap.csv");
|
|
var sql = $@"TRUNCATE raw_node_map;
|
|
COPY raw_node_map(level, node_class, name, node_id)
|
|
FROM '{csvPath}'
|
|
DELIMITER ',' CSV HEADER;";
|
|
using var cmd = new NpgsqlCommand(sql, conn);
|
|
await cmd.ExecuteNonQueryAsync();
|
|
return Ok(new { message = "DB 동기화 완료" });
|
|
}
|
|
catch (Exception ex) { return BadRequest(ex.Message); }
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region [신규 기능: 하니웰 전용 인증서 관리]
|
|
|
|
[HttpGet("CertManager")]
|
|
public IActionResult CertManager()
|
|
{
|
|
string pfxPath = Path.Combine(_basePath, "pki/own/private/OpcTestClient.pfx");
|
|
|
|
// 파일 존재 여부를 ViewData에 담아 보냅니다.
|
|
ViewBag.IsCertExists = System.IO.File.Exists(pfxPath);
|
|
|
|
ViewBag.SuccessMsg = TempData["Success"];
|
|
ViewBag.ErrorMsg = TempData["Error"];
|
|
return View(new CertRequestModel());
|
|
}
|
|
|
|
[HttpPost("GenerateCertificate")]
|
|
public async Task<IActionResult> GenerateCertificate(CertRequestModel model)
|
|
{
|
|
try
|
|
{
|
|
var generator = new CertificateGenerator(_basePath);
|
|
var success = await generator.CreateHoneywellCertificateAsync(model);
|
|
|
|
if (success) {
|
|
TempData["Success"] = "하니웰 FTE 대응 인증서가 생성 및 백업되었습니다.";
|
|
return RedirectToAction("CertManager");
|
|
}
|
|
|
|
TempData["Error"] = "인증서 생성 중 오류가 발생했습니다.";
|
|
return RedirectToAction("CertManager");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
TempData["Error"] = ex.Message;
|
|
return RedirectToAction("CertManager");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
public class SearchRequest { public string TagTerm { get; set; } public List<string> Suffixes { get; set; } }
|
|
public class TagRegistrationRequest { public string TagName { get; set; } public string NodeId { get; set; } public string DataType { get; set; } }
|
|
} |