TIMESTAMP에 현재시간 적용 기능 추가

This commit is contained in:
logonkhi
2025-07-21 11:51:16 +09:00
parent 2d7bcab187
commit 6fcf7d6d46
6 changed files with 54 additions and 10 deletions

View File

@@ -25,6 +25,12 @@ namespace XRServer
// 정규식은 매번 컴파일하지 않고, static readonly으로 만들어 한 번만 컴파일하여 재사용하는 것이 성능에 유리합니다.
private static readonly Regex TimeFormatRegex = new Regex(@"([0-5][0-9]):([0-5][0-9])$", RegexOptions.Compiled);
/// <summary>
/// 지정된 콘텐츠의 모든 TIMESTAMP 발생을 현재 시간 UTC TIMESTAMP로 바꿀지 여부
/// </summary>
public bool ApplyNowTimeStamp { get; set; } = false; // 현재 시간 스탬프를 적용하지 않습니다.
/// <summary>
/// BaseInfoHandler의 생성자입니다.
/// </summary>
@@ -70,7 +76,8 @@ namespace XRServer
try
{
// 4. 데이터베이스에서 가져온 JSON 문자열을 JObject로 파싱(변환)합니다.
var jsonData = JObject.Parse(data[0].data);
string jsonString = !ApplyNowTimeStamp ? data[0].data : DateTimeUtil.ChangedTimeStampToNow(data[0].data);
var jsonData = JObject.Parse(jsonString);
object responseData = null; // 최종적으로 클라이언트에게 보낼 데이터
// 5. 요청 타입에 따라 반환할 데이터를 결정합니다.

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
namespace XRServer
@@ -135,5 +136,26 @@ namespace XRServer
{
return DateTime.ParseExact(dateTimeString, formatString, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
}
/// <summary>
/// 지정된 콘텐츠의 모든 TIMESTAMP 발생을 현재 시간 UTC TIMESTAMP로 바꿉니다.
/// </summary>
/// <remarks>이 메서드는 "TIMESTAMP":"yyyy-MM-ddTHH:mm:ss", "yyyy-MM-ddTHH:mm:ss.fffZ" 형식의 타임스탬프를 검색하여
/// 동일한 형식의 현재 UTC 시간으로 바꿉니다.</remarks>
/// <param name="content">업데이트할 타임스탬프가 포함된 문자열 콘텐츠입니다.</param>
/// <param name="isUTC">현재 시간을 UTC로 사용할지 여부를 나타내는 부울 값입니다. 기본값은 false입니다.</param>
/// <returns>모든 타임스탬프가 현재 UTC 타임스탬프로 바뀐 새 문자열입니다.</returns>
public static string ChangedTimeStampToNow(string content, bool isUTC = false)
{
DateTime now = isUTC ? DateTime.UtcNow : DateTime.Now;
// yyyy-MM-ddTHH:mm:ss.fffZ 형식 처리
content = Regex.Replace(content, @"TIMESTAMP"":""\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z""", $"TIMESTAMP\":\"{now:yyyy-MM-ddTHH:mm:ss.fffZ}\"");
// yyyy-MM-ddTHH:mm:ss 형식 처리
content = Regex.Replace(content, @"TIMESTAMP"":""\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}""", $"TIMESTAMP\":\"{now:yyyy-MM-ddTHH:mm:ss}\"");
return content;
}
}
}

View File

@@ -5,6 +5,7 @@ using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Buffers;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Windows;
using utils;
@@ -36,6 +37,8 @@ namespace XRServer
private TimeSpan _currentPlaybackTime = TimeSpan.Zero;
private CancellationTokenSource _timerCts;
private Task _timerTask;
// TIMESTAMP(yyyy-MM-ddTHH:mm:ss 2025-03-25T13:00:51)에 현재 시간을 적용 할것인지 여부
private bool applyNow = false;
/// <summary>
/// 매 타임틱마다 호출할 작업을 가져오거나 설정합니다.
@@ -200,10 +203,12 @@ namespace XRServer
if (data != null && data.Count > 0)
{
string messageData = !applyNow ? data[0].data : DateTimeUtil.ChangedTimeStampToNow(data[0].data);
// 전체 토픽 메시지
var messageAll = new MqttApplicationMessageBuilder()
.WithTopic(topic)
.WithPayload(data[0].data)
.WithPayload(messageData)
.WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce)
.WithRetainFlag(false)
.Build();
@@ -213,7 +218,7 @@ namespace XRServer
// 개별 프로퍼티 메시지
// json 변환
JObject? jsonObject = JsonConvert.DeserializeObject<JObject>(data[0].data);
JObject? jsonObject = JsonConvert.DeserializeObject<JObject>(messageData);
if (jsonObject != null)
{
string topicString = "";
@@ -262,8 +267,9 @@ namespace XRServer
}
}
public async Task Start(string? startTime = null)
public async Task Start(string? startTime = null, bool applyNow = false)
{
this.applyNow = applyNow;
if (mqttServer != null)
{
if (!string.IsNullOrEmpty(startTime)) SetStartTime(startTime);

View File

@@ -5,9 +5,9 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:XRServer"
mc:Ignorable="d"
Title="XR Server" Height="400" Width="840" Closing="Window_Closing" Loaded="Window_Loaded">
Title="XR Server" Height="450" Width="840" Closing="Window_Closing" Loaded="Window_Loaded">
<Grid>
<Button x:Name="startBtn" Content="Start" HorizontalAlignment="Left" Margin="20,268,0,0" VerticalAlignment="Top" Width="247" Height="35" Click="startBtn_Click"/>
<Button x:Name="startBtn" Content="Start" HorizontalAlignment="Left" Margin="20,318,0,0" VerticalAlignment="Top" Width="247" Height="35" Click="startBtn_Click"/>
<Button x:Name="startTimeBtn" Content="MQTT 시간 변경" HorizontalAlignment="Left" Margin="147,225,0,0" VerticalAlignment="Top" Width="120" Height="25" Click="startTimeBtn_Click"/>
<Label Content="HTTP Port" HorizontalAlignment="Left" Margin="20,74,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="httpPortTxt" HorizontalAlignment="Left" Margin="147,80,0,0" TextWrapping="Wrap" Text="8888" VerticalAlignment="Top" Width="120" Height="20" TextChanged="httpPortTxt_TextChanged"/>
@@ -23,7 +23,8 @@
<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"/>
<ScrollViewer HorizontalAlignment="Left" Margin="300,43,0,0" VerticalAlignment="Top" Width="250" Height="260">
<CheckBox x:Name="checkboxTimestamp" Content="TIMESTAMP에 현재 시간 적용" HorizontalAlignment="Left" Margin="22,271,0,0" VerticalAlignment="Top"/>
<ScrollViewer HorizontalAlignment="Left" Margin="300,43,0,0" VerticalAlignment="Top" Width="250" Height="310">
<RichTextBox x:Name="httpLinkTxtBlock" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto"
IsReadOnly="True" IsDocumentEnabled="True">
<FlowDocument>
@@ -39,7 +40,7 @@
</FlowDocument>
</RichTextBox>
</ScrollViewer>
<ScrollViewer HorizontalAlignment="Left" Margin="560,43,0,0" VerticalAlignment="Top" Width="250" Height="260">
<ScrollViewer HorizontalAlignment="Left" Margin="560,43,0,0" VerticalAlignment="Top" Width="250" Height="310">
<RichTextBox x:Name="mqttLinkTxtBlock" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility="Auto"
IsReadOnly="True" IsDocumentEnabled="True">
<FlowDocument>
@@ -55,5 +56,6 @@
</FlowDocument>
</RichTextBox>
</ScrollViewer>
</Grid>
</Window>

View File

@@ -33,6 +33,8 @@ namespace XRServer
private string sqliteDbPath = string.Empty; // SQLite 데이터베이스 경로
private BaseInfoHandler httpHandler;
public MainWindow()
{
InitializeComponent();
@@ -107,11 +109,12 @@ namespace XRServer
httpPort = int.Parse(httpPortTxt.Text);
mqttPort = int.Parse(mqttPortTxt.Text);
Logger.Debug($"Start Server httpPort:{httpPort} mqttPort:{mqttPort}");
httpHandler.ApplyNowTimeStamp = checkboxTimestamp.IsChecked ?? false;
httpServer.Start();
// MQTT 서버 시작
mqttService.SetConfig(mqttPort, mqttTopicTxt.Text, mqttTopicTxt2.Text);
await mqttService.Start(mqttStartTimeTxt.Text);
await mqttService.Start(mqttStartTimeTxt.Text, checkboxTimestamp.IsChecked ?? false);
startBtn.Content = "Stop";
httpPortTxt.IsEnabled = false;
@@ -120,6 +123,7 @@ namespace XRServer
mqttLink.IsEnabled = true;
mqttTopicTxt.IsEnabled = false;
mqttTopicTxt2.IsEnabled = false;
checkboxTimestamp.IsEnabled = false;
}
else
{
@@ -136,6 +140,7 @@ namespace XRServer
mqttLink.IsEnabled = false;
mqttTopicTxt.IsEnabled = true;
mqttTopicTxt2.IsEnabled = true;
checkboxTimestamp.IsEnabled = true;
}
isRunning = !isRunning;
@@ -156,8 +161,9 @@ namespace XRServer
private void InitHttpServer()
{
httpHandler = new BaseInfoHandler(sqliteService);
httpServer.Use(new TcpListenerAdapter(new TcpListener(IPAddress.Loopback, httpPort)));
httpServer.Use(new BaseInfoHandler(sqliteService));
httpServer.Use(httpHandler);
}
private void dbFileLoadBtn_Click(object sender, RoutedEventArgs e)

View File

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