addressable 로컬 테스트를 위한 서버 기능 추가. 버전업

This commit is contained in:
logonkhi
2025-12-01 20:27:38 +09:00
parent 1ba0bb599b
commit f3f175fe10
4 changed files with 104 additions and 20 deletions

View File

@@ -35,6 +35,16 @@ namespace XRServer
/// </summary>
public string PlaybackFolderPath { get; set; } = string.Empty;
/// <summary>
/// Unity3d Addressable http 경로
/// </summary>
public string AddressableHttpPathTxt { get; set; } = "/addressable";
/// <summary>
/// Unity3d Addressable 파일 경로
/// </summary>
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<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("Content-Disposition", $"attachment; filename=\"{fileName}\""),
new KeyValuePair<string, string>("Content-Length", fileBytes.Length.ToString()), // 데이터의 크기
new KeyValuePair<string, string>("Access-Control-Allow-Origin", "*") // CORS 헤더 추가
};
context.Response = new HttpResponse(
HttpResponseCode.Ok,
"application/octet-stream",
new MemoryStream(fileBytes),
context.Request.Headers.KeepAliveConnection(),
headers);
}
/// <summary>
/// URL 경로에서 요청 타입을 추출합니다. (예: "baseinfo")
/// </summary>

View File

@@ -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">
<Grid>
<Button x:Name="startBtn" Content="Start" HorizontalAlignment="Left" Margin="20,353,0,0" VerticalAlignment="Top" Width="247" Height="25" Click="startBtn_Click"/>
<Button x:Name="startTimeBtn" Content="MQTT 시간 변경" HorizontalAlignment="Left" Margin="161,277,0,0" VerticalAlignment="Top" Width="106" Height="25" Click="startTimeBtn_Click"/>
<Label Content="HTTP Port" HorizontalAlignment="Left" Margin="20,101,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="httpPortTxt" HorizontalAlignment="Left" Margin="161,107,0,0" TextWrapping="Wrap" Text="8888" VerticalAlignment="Top" Width="106" Height="20" TextChanged="httpPortTxt_TextChanged"/>
<Label Content="MQTT Port" HorizontalAlignment="Left" Margin="20,132,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="mqttPortTxt" HorizontalAlignment="Left" Margin="161,135,0,0" TextWrapping="Wrap" Text="1883" VerticalAlignment="Top" Width="106" Height="20" TextChanged="mqttPortTxt_TextChanged"/>
<Label Content="MQTT WebSocket Port" HorizontalAlignment="Left" Margin="20,157,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="mqttWebSocketPortTxt" HorizontalAlignment="Left" Margin="161,160,0,0" TextWrapping="Wrap" Text="8083" VerticalAlignment="Top" Width="106" Height="20" TextChanged="mqttWebSocketPortTxt_TextChanged"/>
<Label Content="MQTT Topic" HorizontalAlignment="Left" Margin="20,187,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="mqttTopicTxt" HorizontalAlignment="Left" Margin="161,190,0,0" TextWrapping="Wrap" Text="newXR" VerticalAlignment="Top" Width="106" Height="20" TextChanged="mqttPortTxt_TextChanged"/>
<Label Content="MQTT Start Topic" HorizontalAlignment="Left" Margin="20,217,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="mqttTopicTxt2" HorizontalAlignment="Left" Margin="161,220,0,0" TextWrapping="Wrap" Text="startTime" VerticalAlignment="Top" Width="106" Height="20" TextChanged="mqttPortTxt_TextChanged"/>
<Label Content="MQTT Start Time" HorizontalAlignment="Left" Margin="20,247,0,0" VerticalAlignment="Top"/>
<Label x:Name="nowTimeTxt" Content="Now 00:00" HorizontalAlignment="Left" Margin="20,277,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="mqttStartTimeTxt" HorizontalAlignment="Left" Margin="161,250,0,0" TextWrapping="Wrap" Text="00:00" VerticalAlignment="Top" Width="106" Height="20" TextChanged="mqttPortTxt_TextChanged"/>
<Button x:Name="startBtn" Content="Start" HorizontalAlignment="Left" Margin="20,418,0,0" VerticalAlignment="Top" Width="247" Height="25" Click="startBtn_Click"/>
<Button x:Name="startTimeBtn" Content="MQTT 시간 변경" HorizontalAlignment="Left" Margin="161,342,0,0" VerticalAlignment="Top" Width="106" Height="25" Click="startTimeBtn_Click"/>
<Label Content="HTTP Port" HorizontalAlignment="Left" Margin="20,133,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="httpPortTxt" HorizontalAlignment="Left" Margin="161,139,0,0" TextWrapping="Wrap" Text="8888" VerticalAlignment="Top" Width="106" Height="20" TextChanged="httpPortTxt_TextChanged"/>
<Label Content="HTTP Addressable Path" HorizontalAlignment="Left" Margin="20,163,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="addressableHttpPathTxt" HorizontalAlignment="Left" Margin="161,169,0,0" TextWrapping="Wrap" Text="/addressable" VerticalAlignment="Top" Width="106" Height="20" TextChanged="addressablePathTxt_TextChanged"/>
<Label Content="MQTT Port" HorizontalAlignment="Left" Margin="20,197,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="mqttPortTxt" HorizontalAlignment="Left" Margin="161,200,0,0" TextWrapping="Wrap" Text="1883" VerticalAlignment="Top" Width="106" Height="20" TextChanged="mqttPortTxt_TextChanged"/>
<Label Content="MQTT WebSocket Port" HorizontalAlignment="Left" Margin="20,222,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="mqttWebSocketPortTxt" HorizontalAlignment="Left" Margin="161,225,0,0" TextWrapping="Wrap" Text="8083" VerticalAlignment="Top" Width="106" Height="20" TextChanged="mqttWebSocketPortTxt_TextChanged"/>
<Label Content="MQTT Topic" HorizontalAlignment="Left" Margin="20,252,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="mqttTopicTxt" HorizontalAlignment="Left" Margin="161,255,0,0" TextWrapping="Wrap" Text="newXR" VerticalAlignment="Top" Width="106" Height="20" TextChanged="mqttPortTxt_TextChanged"/>
<Label Content="MQTT Start Topic" HorizontalAlignment="Left" Margin="20,282,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="mqttTopicTxt2" HorizontalAlignment="Left" Margin="161,285,0,0" TextWrapping="Wrap" Text="startTime" VerticalAlignment="Top" Width="106" Height="20" TextChanged="mqttPortTxt_TextChanged"/>
<Label Content="MQTT Start Time" HorizontalAlignment="Left" Margin="20,312,0,0" VerticalAlignment="Top"/>
<Label x:Name="nowTimeTxt" Content="Now 00:00" HorizontalAlignment="Left" Margin="20,342,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="mqttStartTimeTxt" HorizontalAlignment="Left" Margin="161,315,0,0" TextWrapping="Wrap" Text="00:00" VerticalAlignment="Top" Width="106" Height="20" TextChanged="mqttPortTxt_TextChanged"/>
<Label Content="DB File" HorizontalAlignment="Left" Margin="20,20,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="dbPathTxt" HorizontalAlignment="Left" Margin="20,43,0,0" VerticalAlignment="Top" TextWrapping="Wrap" Text="" Width="180" Height="20" IsReadOnly="True"/>
<Button x:Name="dbFileLoadBtn" Content="설정" HorizontalAlignment="Left" Margin="212,43,0,0" VerticalAlignment="Top" Width="55" Height="20" Click="dbFileLoadBtn_Click"/>
<TextBox x:Name="playbackPathTxt" HorizontalAlignment="Left" Margin="20,73,0,0" VerticalAlignment="Top" TextWrapping="Wrap" Text="" Width="120" Height="20" IsReadOnly="True"/>
<Button x:Name="playbackFolderBtn" Content="Playback 폴더 설정" HorizontalAlignment="Left" Margin="152,73,0,0" VerticalAlignment="Top" Width="115" Height="20" Click="playbackFolderBtn_Click"/>
<CheckBox x:Name="UseWebSocket" Content="WebSocket도 사용" HorizontalAlignment="Left" Margin="22,313,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="UseVTMFormat" Content="VTM 포맷 적용" HorizontalAlignment="Left" Margin="156,313,0,0" VerticalAlignment="Top" IsChecked="True"/>
<CheckBox x:Name="checkboxTimestamp" Content="TIMESTAMP에 현재 시간 적용" HorizontalAlignment="Left" Margin="22,333,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="addressablePathTxt" HorizontalAlignment="Left" Margin="20,103,0,0" VerticalAlignment="Top" TextWrapping="Wrap" Text="" Width="120" Height="20" IsReadOnly="True"/>
<Button x:Name="addressableFolderBtn" Content="Addressable 폴더 설정" HorizontalAlignment="Left" Margin="152,103,0,0" VerticalAlignment="Top" Width="115" Height="20" Click="addressableFolderBtn_Click"/>
<CheckBox x:Name="UseWebSocket" Content="WebSocket도 사용" HorizontalAlignment="Left" Margin="22,378,0,0" VerticalAlignment="Top"/>
<CheckBox x:Name="UseVTMFormat" Content="VTM 포맷 적용" HorizontalAlignment="Left" Margin="156,378,0,0" VerticalAlignment="Top" IsChecked="True"/>
<CheckBox x:Name="checkboxTimestamp" Content="TIMESTAMP에 현재 시간 적용" HorizontalAlignment="Left" Margin="22,398,0,0" VerticalAlignment="Top"/>
<ScrollViewer HorizontalAlignment="Left" Margin="300,43,0,0" VerticalAlignment="Top" Width="250" Height="335">
<RichTextBox x:Name="httpLinkTxtBlock" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto"
IsReadOnly="True" IsDocumentEnabled="True" Height="334">

View File

@@ -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);
}
}
}
}

View File

@@ -8,7 +8,7 @@
<UseWPF>true</UseWPF>
<Platforms>AnyCPU;x86</Platforms>
<ApplicationIcon>icon.ico</ApplicationIcon>
<Version>1.0.7</Version>
<Version>1.0.8</Version>
</PropertyGroup>
<ItemGroup>