diff --git a/XRServer/HttpHandler.cs b/XRServer/HttpHandler.cs
index e563354..b5d756e 100644
--- a/XRServer/HttpHandler.cs
+++ b/XRServer/HttpHandler.cs
@@ -35,6 +35,16 @@ namespace XRServer
///
public string PlaybackFolderPath { get; set; } = string.Empty;
+ ///
+ /// Unity3d Addressable http 경로
+ ///
+ public string AddressableHttpPathTxt { get; set; } = "/addressable";
+
+ ///
+ /// Unity3d Addressable 파일 경로
+ ///
+ public string AddressablePathTxt { get; set; } = string.Empty;
+
private string currentMMSS = "00:00";
public string CurrentMMSS
{
@@ -69,6 +79,17 @@ namespace XRServer
string url = context.Request.Uri.OriginalString;
Logger.Debug($"HttpHandler: {url} 요청 처리 중...");
+ // Addressable 파일 요청 처리
+ if(url.StartsWith(AddressableHttpPathTxt, StringComparison.OrdinalIgnoreCase))
+ {
+ // URL에서 "/addressable/" 접두사를 제외한 나머지 부분을 파일 이름으로 추출합니다.
+ string fileName = url.Substring($"{AddressableHttpPathTxt}/".Length);
+ // 파일 이름에 포함될 수 있는 URL 인코딩(예: %20)을 디코딩합니다.
+ string decodedFileName = System.Net.WebUtility.UrlDecode(fileName);
+ handleAddressableFile(context, decodedFileName);
+ return; // '/addressable/' 요청은 별도로 처리하므로 여기서 종료합니다.
+ }
+
//url이 '/playback/list'로 시작하는 경우, 다음 핸들러로 넘깁니다.
if (url.StartsWith("/playback/list", StringComparison.OrdinalIgnoreCase))
{
@@ -229,6 +250,32 @@ namespace XRServer
headers);
}
+ private void handleAddressableFile(IHttpContext context, string fileName)
+ {
+ // AddressablePathTxt 경로에서 요청된 파일이 존재하는지 확인합니다.
+ string filePath = Path.Combine(AddressablePathTxt, fileName);
+ if (!File.Exists(filePath))
+ {
+ // 파일이 없으면 404 오류를 반환합니다.
+ context.Response = new HttpResponse(HttpResponseCode.NotFound, "요청한 Addressable 파일을 찾을 수 없습니다.", false);
+ return;
+ }
+ // 파일이 존재하면 해당 파일을 읽어 응답으로 보냅니다.
+ byte[] fileBytes = File.ReadAllBytes(filePath);
+ var headers = new List>
+ {
+ new KeyValuePair("Content-Disposition", $"attachment; filename=\"{fileName}\""),
+ new KeyValuePair("Content-Length", fileBytes.Length.ToString()), // 데이터의 크기
+ new KeyValuePair("Access-Control-Allow-Origin", "*") // CORS 헤더 추가
+ };
+ context.Response = new HttpResponse(
+ HttpResponseCode.Ok,
+ "application/octet-stream",
+ new MemoryStream(fileBytes),
+ context.Request.Headers.KeepAliveConnection(),
+ headers);
+ }
+
///
/// URL 경로에서 요청 타입을 추출합니다. (예: "baseinfo")
///
diff --git a/XRServer/MainWindow.xaml b/XRServer/MainWindow.xaml
index d8c165d..e8ae728 100644
--- a/XRServer/MainWindow.xaml
+++ b/XRServer/MainWindow.xaml
@@ -5,31 +5,35 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:XRServer"
mc:Ignorable="d"
- Title="XR Server" Height="470" Width="840" Closing="Window_Closing" Loaded="Window_Loaded">
+ Title="XR Server" Height="530" Width="840" Closing="Window_Closing" Loaded="Window_Loaded">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
diff --git a/XRServer/MainWindow.xaml.cs b/XRServer/MainWindow.xaml.cs
index 4c2ec51..f06f914 100644
--- a/XRServer/MainWindow.xaml.cs
+++ b/XRServer/MainWindow.xaml.cs
@@ -73,6 +73,7 @@ namespace XRServer
sqliteDbPath = ini.GetString("CONFIG", "DB_PATH").Trim();
dbPathTxt.Text = sqliteDbPath;
playbackFolderPath = ini.GetString("CONFIG", "PLAYBACK_PATH").Trim();
+ addressablePathTxt.Text = ini.GetString("CONFIG", "ADDRESSABLE_PATH").Trim();
playbackPathTxt.Text = playbackFolderPath;
startBtn.IsEnabled = sqliteDbPath != string.Empty && playbackFolderPath != string.Empty && File.Exists(sqliteDbPath) && Directory.Exists(playbackFolderPath);
@@ -118,6 +119,8 @@ namespace XRServer
Logger.Debug($"Start Server httpPort:{httpPort} {(useWS ? "wsPort" : "mqttPort")}:{mqttPort}, mqttWebSocketPort:{mqttWebSocketPort}");
httpHandler.ApplyNowTimeStamp = checkboxTimestamp.IsChecked ?? false;
httpHandler.PlaybackFolderPath = playbackFolderPath;
+ httpHandler.AddressableHttpPathTxt = addressableHttpPathTxt.Text.Trim();
+ httpHandler.AddressablePathTxt = addressablePathTxt.Text.Trim();
httpServer.Start();
// MQTT 또는 WebSocket 서버 시작 (여기서 인스턴스 생성)
@@ -148,6 +151,9 @@ namespace XRServer
mqttLink.IsEnabled = true;
mqttTopicTxt.IsEnabled = false;
mqttTopicTxt2.IsEnabled = false;
+ addressableHttpPathTxt.IsEnabled = false;
+ addressablePathTxt.IsEnabled = false;
+ addressableFolderBtn.IsEnabled = false;
checkboxTimestamp.IsEnabled = false;
UseWebSocket.IsEnabled = false;
}
@@ -176,6 +182,9 @@ namespace XRServer
mqttLink.IsEnabled = false;
mqttTopicTxt.IsEnabled = true;
mqttTopicTxt2.IsEnabled = true;
+ addressableHttpPathTxt.IsEnabled = true;
+ addressablePathTxt.IsEnabled = true;
+ addressableFolderBtn.IsEnabled = true;
checkboxTimestamp.IsEnabled = true;
UseWebSocket.IsEnabled = true;
}
@@ -447,5 +456,29 @@ namespace XRServer
startBtn.IsEnabled = sqliteDbPath != string.Empty && playbackFolderPath != string.Empty && File.Exists(sqliteDbPath) && Directory.Exists(playbackFolderPath);
}
}
+
+ private void addressablePathTxt_TextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
+ {
+
+ }
+
+ private void addressableFolderBtn_Click(object sender, RoutedEventArgs e)
+ {
+ // SQLite 데이터베이스 파일 선택 대화상자 열기
+ var dialog = new Microsoft.Win32.OpenFolderDialog();
+
+ // Show open file dialog box
+ bool? result = dialog.ShowDialog();
+
+ // Process open file dialog box results
+ if (result == true)
+ {
+ // Open document
+ addressablePathTxt.Text = dialog.FolderName;
+ ini.SetString("CONFIG", "ADDRESSABLE_PATH", addressablePathTxt.Text);
+
+ startBtn.IsEnabled = sqliteDbPath != string.Empty && playbackFolderPath != string.Empty && File.Exists(sqliteDbPath) && Directory.Exists(playbackFolderPath);
+ }
+ }
}
}
\ No newline at end of file
diff --git a/XRServer/XRServer.csproj b/XRServer/XRServer.csproj
index b9fa99e..6a3a2d9 100644
--- a/XRServer/XRServer.csproj
+++ b/XRServer/XRServer.csproj
@@ -8,7 +8,7 @@
true
AnyCPU;x86
icon.ico
- 1.0.7
+ 1.0.8