using System; using System.Collections.Generic; using System.Web.Http; using System.Linq; using System.Net.Http; using System.Net; using System.IO; using System.Drawing; using System.Drawing.Drawing2D; using System.Drawing.Imaging; using VNCServerList.Models; using VNCServerList.Services; namespace VNCServerList.Web.Controllers { [RoutePrefix("api/vncserver")] public class VNCServerController : ApiController { private readonly DatabaseService _databaseService; private readonly VNCService _vncService; private readonly SettingsService _settingsService; public VNCServerController() { _settingsService = new SettingsService(); _databaseService = new DatabaseService(); _vncService = new VNCService(_databaseService, _settingsService); } [HttpGet] [Route("list")] public IHttpActionResult GetServerList(string userName = null) { try { var servers = _databaseService.GetAllServers(); // 사용자 이름이 있으면 필터링 if (!string.IsNullOrEmpty(userName)) { servers = servers.Where(s => s.User.Equals(userName, StringComparison.OrdinalIgnoreCase)).ToList(); } // 사용자명으로 오름차순 정렬 var sortedServers = servers.OrderBy(s => s.User).ThenBy(s => s.IP).ToList(); return Ok(sortedServers); } catch (Exception ex) { return InternalServerError(ex); } } [HttpGet] [Route("get/{user}/{ip}")] public IHttpActionResult GetServer(string user, string ip) { try { var server = _databaseService.GetServerByUserAndIP(user, ip); if (server == null) { return NotFound(); } return Ok(server); } catch (Exception ex) { return InternalServerError(ex); } } [HttpPost] [Route("add")] public IHttpActionResult AddServer([FromBody] VNCServer server) { try { if (server == null) { return BadRequest("서버 정보가 없습니다."); } // 아이콘이 Base64로 전송된 경우 처리 if (!string.IsNullOrEmpty(server.IconBase64)) { try { var iconData = Convert.FromBase64String(server.IconBase64); server.Icon = ResizeImage(iconData, 128, 128); } catch { return BadRequest("아이콘 데이터 형식이 올바르지 않습니다."); } } bool success = _databaseService.AddServer(server); if (success) { return Ok(new { Message = "서버가 성공적으로 추가되었습니다." }); } else { return BadRequest("서버 추가에 실패했습니다."); } } catch (Exception ex) { return InternalServerError(ex); } } [HttpPut] [Route("update/{originalUser}/{originalIp}")] public IHttpActionResult UpdateServer(string originalUser, string originalIp, [FromBody] VNCServer server) { try { if (server == null) { return BadRequest("서버 정보가 없습니다."); } // 아이콘이 Base64로 전송된 경우 처리 if (!string.IsNullOrEmpty(server.IconBase64)) { try { var iconData = Convert.FromBase64String(server.IconBase64); server.Icon = ResizeImage(iconData, 128, 128); } catch { return BadRequest("아이콘 데이터 형식이 올바르지 않습니다."); } } // 원본 사용자명과 IP로 서버를 찾아서 업데이트 bool success = _databaseService.UpdateServerByUserAndIP(originalUser, originalIp, server); if (success) { return Ok(new { Message = "서버가 성공적으로 업데이트되었습니다." }); } else { return NotFound(); } } catch (Exception ex) { return InternalServerError(ex); } } [HttpDelete] [Route("delete/{user}/{ip}")] public IHttpActionResult DeleteServer(string user, string ip) { try { bool success = _databaseService.DeleteServer(user, ip); if (success) { return Ok(new { Message = "서버가 성공적으로 삭제되었습니다." }); } else { return NotFound(); } } catch (Exception ex) { return InternalServerError(ex); } } [HttpPost] [Route("connect/{user}/{ip}")] public IHttpActionResult ConnectToServer(string user, string ip) { try { bool success = _vncService.ConnectToServer(user, ip); if (success) { return Ok(new { Message = "VNC 연결이 시작되었습니다." }); } else { return BadRequest("VNC 연결에 실패했습니다."); } } catch (Exception ex) { return InternalServerError(ex); } } [HttpGet] [Route("vnc-status")] public IHttpActionResult GetVNCStatus() { try { bool isInstalled = _vncService.IsVNCViewerInstalled(); string path = _vncService.GetVNCViewerPath(); return Ok(new { IsInstalled = isInstalled, Path = path }); } catch (Exception ex) { return InternalServerError(ex); } } [HttpPost] [Route("set-vnc-path")] public IHttpActionResult SetVNCPath([FromBody] VNCPathRequest data) { try { string path = data.Path; if (string.IsNullOrEmpty(path)) { return BadRequest("VNC Viewer 경로가 제공되지 않았습니다."); } _vncService.SetVNCViewerPath(path); return Ok(new { Message = "VNC Viewer 경로가 설정되었습니다." }); } catch (Exception ex) { return InternalServerError(ex); } } [HttpGet] [Route("settings")] public IHttpActionResult GetSettings() { try { System.Diagnostics.Debug.WriteLine("=== 설정 조회 시작 ==="); var settings = _settingsService.GetSettings(); // 디버깅용 로그 System.Diagnostics.Debug.WriteLine($"조회된 설정: VNCViewerPath='{settings.VNCViewerPath}', WebServerPort={settings.WebServerPort}"); System.Diagnostics.Debug.WriteLine("=== 설정 조회 완료 ==="); return Ok(settings); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"설정 조회 오류: {ex.Message}"); System.Diagnostics.Debug.WriteLine($"스택 트레이스: {ex.StackTrace}"); return InternalServerError(ex); } } [HttpPost] [Route("settings")] public IHttpActionResult UpdateSettings([FromBody] AppSettings settings) { try { System.Diagnostics.Debug.WriteLine("=== 설정 저장 요청 시작 ==="); if (settings == null) { System.Diagnostics.Debug.WriteLine("설정 객체가 null입니다."); return BadRequest("설정 정보가 없습니다."); } // 디버깅용 로그 System.Diagnostics.Debug.WriteLine($"받은 설정 데이터: VNCViewerPath='{settings.VNCViewerPath}', WebServerPort={settings.WebServerPort}"); System.Diagnostics.Debug.WriteLine($"VNCViewerPath 타입: {settings.VNCViewerPath?.GetType()}"); System.Diagnostics.Debug.WriteLine($"WebServerPort 타입: {settings.WebServerPort.GetType()}"); _settingsService.SaveSettings(settings); // 저장된 설정 확인 var savedSettings = _settingsService.GetSettings(); System.Diagnostics.Debug.WriteLine($"저장된 설정: VNCViewerPath='{savedSettings.VNCViewerPath}', WebServerPort={savedSettings.WebServerPort}"); System.Diagnostics.Debug.WriteLine("=== 설정 저장 완료 ==="); return Ok(new { Message = "설정이 저장되었습니다." }); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"설정 저장 오류: {ex.Message}"); System.Diagnostics.Debug.WriteLine($"스택 트레이스: {ex.StackTrace}"); return InternalServerError(ex); } } [HttpGet] [Route("icon/{user}/{ip}")] public HttpResponseMessage GetServerIcon(string user, string ip) { try { var server = _databaseService.GetServerByUserAndIP(user, ip); if (server?.Icon == null || server.Icon.Length == 0) { return Request.CreateResponse(HttpStatusCode.NotFound); } var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = new ByteArrayContent(server.Icon); response.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("image/png"); return response; } catch (Exception ex) { return Request.CreateResponse(HttpStatusCode.InternalServerError, ex.Message); } } private byte[] ResizeImage(byte[] imageData, int maxWidth = 128, int maxHeight = 128) { using (var originalStream = new MemoryStream(imageData)) using (var originalImage = Image.FromStream(originalStream)) { // 원본 이미지 크기 int originalWidth = originalImage.Width; int originalHeight = originalImage.Height; // 리사이즈가 필요한지 확인 if (originalWidth <= maxWidth && originalHeight <= maxHeight) { return imageData; // 리사이즈 불필요 } // 새로운 크기 계산 (비율 유지) double ratioX = (double)maxWidth / originalWidth; double ratioY = (double)maxHeight / originalHeight; double ratio = Math.Min(ratioX, ratioY); int newWidth = (int)(originalWidth * ratio); int newHeight = (int)(originalHeight * ratio); // 새 이미지 생성 using (var resizedImage = new Bitmap(newWidth, newHeight)) using (var graphics = Graphics.FromImage(resizedImage)) { // 고품질 리사이즈 설정 graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.SmoothingMode = SmoothingMode.HighQuality; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; // 이미지 그리기 graphics.DrawImage(originalImage, 0, 0, newWidth, newHeight); // PNG로 변환하여 반환 using (var outputStream = new MemoryStream()) { resizedImage.Save(outputStream, ImageFormat.Png); return outputStream.ToArray(); } } } } [HttpPost] [Route("icon/{user}/{ip}")] public IHttpActionResult UploadServerIcon(string user, string ip) { try { var httpRequest = System.Web.HttpContext.Current.Request; if (httpRequest.Files.Count == 0) { return BadRequest("업로드된 파일이 없습니다."); } var file = httpRequest.Files[0]; if (file.ContentLength > 1024 * 1024) // 1MB 제한 { return BadRequest("파일 크기는 1MB를 초과할 수 없습니다."); } using (var memoryStream = new MemoryStream()) { file.InputStream.CopyTo(memoryStream); var originalIconData = memoryStream.ToArray(); // 이미지 리사이즈 (128x128로 제한) var resizedIconData = ResizeImage(originalIconData, 128, 128); var server = _databaseService.GetServerByUserAndIP(user, ip); if (server == null) { return NotFound(); } server.Icon = resizedIconData; bool success = _databaseService.UpdateServer(server); if (success) { return Ok(new { Message = "아이콘이 성공적으로 업로드되었습니다." }); } else { return BadRequest("아이콘 업로드에 실패했습니다."); } } } catch (Exception ex) { return InternalServerError(ex); } } [HttpDelete] [Route("icon/{user}/{ip}")] public IHttpActionResult DeleteServerIcon(string user, string ip) { try { var server = _databaseService.GetServerByUserAndIP(user, ip); if (server == null) { return NotFound(); } server.Icon = null; bool success = _databaseService.UpdateServer(server); if (success) { return Ok(new { Message = "아이콘이 성공적으로 삭제되었습니다." }); } else { return BadRequest("아이콘 삭제에 실패했습니다."); } } catch (Exception ex) { return InternalServerError(ex); } } } }