451 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			451 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| 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);
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| } | 
