SampleSmart 1.0.0.0
SampleSmart 사용 방법을 보여 주는 예제 프로젝트입니다.
로딩중...
검색중...
일치하는것 없음
CommunicationSampleRuntime.cs
이 파일의 문서화 페이지로 가기
1using System.Text;
2using System.Windows;
3using Dreamine.Communication.Abstractions.Enums;
4using Dreamine.Communication.Abstractions.Interfaces;
5using Dreamine.Communication.Abstractions.Models;
6using Dreamine.Communication.Abstractions.Options;
7using Dreamine.Communication.Core.Framing;
8using Dreamine.Communication.Core.Protocols;
9using Dreamine.Communication.Core.Resilience;
10using Dreamine.Communication.RabbitMQ.Buses;
11using Dreamine.Communication.RabbitMQ.Options;
12using Dreamine.Communication.Serial.Options;
13using Dreamine.Communication.Serial.Ports;
14using Dreamine.Communication.Sockets.Clients;
15using Dreamine.Communication.Sockets.Enums;
16using Dreamine.Communication.Sockets.Options;
17using Dreamine.Communication.Sockets.Servers;
18using Dreamine.Communication.Sockets.Udp;
19using Dreamine.Communication.Wpf.ViewModels;
20
22
39public sealed class CommunicationSampleRuntime
40{
49 private const string InMemoryChannelName = "InMemory-Communication";
58 private const string InMemoryRouteName = "sample.communication.message";
59
68 private const string RabbitMqChannelName = "RabbitMQ-MessageBus";
77 private const string RabbitMqProtocol = "RabbitMQ";
78
87 private const string DreamineEnvelopeProtocol = "DreamineEnvelope";
96 private const string PlainTextProtocol = "PlainText";
105 private const string RawAvailableProtocol = "RawAvailable";
114 private const string RawJsonProtocol = "RawJson";
115
124 private const int DreamineProtocolPort = 15001;
133 private const int PlainTextProtocolPort = 15002;
142 private const int RawAvailableProtocolPort = 15002;
151 private const int RawJsonProtocolPort = 15003;
152
161 private const int UdpPeerALocalPort = 16001;
170 private const int UdpPeerBLocalPort = 16002;
171
180 private readonly IMessageBus _messageBus;
181
200
209 private IMessageTransport? _tcpServer;
218 private TcpServerTransport? _rawTcpServer;
227 private IMessageTransport? _tcpClient;
236 private UdpTransport? _udpPeerA;
245 private UdpTransport? _udpPeerB;
254 private SerialPortTransport? _serialTransport;
263 private RabbitMqMessageBus? _rabbitMqBus;
264
291 private string _currentServerEncoding = PlainTextProtocolOptions.Utf8EncodingName;
300 private string _currentClientEncoding = PlainTextProtocolOptions.Utf8EncodingName;
309 private TcpServerSendTargetMode _currentServerSendTargetMode = TcpServerSendTargetMode.Broadcast;
345 private string _currentUdpPeerAEncoding = PlainTextProtocolOptions.Utf8EncodingName;
354 private string _currentUdpPeerBEncoding = PlainTextProtocolOptions.Utf8EncodingName;
355
373 private string _currentSerialEncoding = PlainTextProtocolOptions.Utf8EncodingName;
382 private string _currentSerialPortName = string.Empty;
391 private int _currentSerialBaudRate = 9600;
392
401 private string _currentRabbitMqHost = "localhost";
410 private int _currentRabbitMqPort = 5672;
419 private string _currentRabbitMqVirtualHost = "/";
428 private string _currentRabbitMqExchangeName = "dreamine.sample.exchange";
437 private string _currentRabbitMqQueueName = "dreamine.sample.queue";
446 private string _currentRabbitMqRoutingKey = "dreamine.sample.route";
447
472 public CommunicationSampleRuntime(IMessageBus messageBus)
473 {
474 _messageBus = messageBus ?? throw new ArgumentNullException(nameof(messageBus));
475 Monitor = new CommunicationMonitorViewModel();
476
478 }
479
488 public CommunicationMonitorViewModel Monitor { get; }
489
498 public IReadOnlyList<string> TcpProtocols { get; } =
499 [
504 ];
505
514 public IReadOnlyList<string> SerialProtocols { get; } =
515 [
519 ];
520
529 public IReadOnlyList<string> UdpProtocols { get; } =
530 [
535 ];
536
545 public IReadOnlyList<string> TextEncodings { get; } =
546 [
547 PlainTextProtocolOptions.Utf8EncodingName,
548 PlainTextProtocolOptions.KoreanCodePage949EncodingName
549 ];
550
559 public IReadOnlyList<string> TcpServerSendTargetModes { get; } =
560 [
561 nameof(TcpServerSendTargetMode.Broadcast),
562 nameof(TcpServerSendTargetMode.FirstClient),
563 nameof(TcpServerSendTargetMode.LastClient)
564 ];
565
574 public IReadOnlyList<string> UdpTextEncodings => TextEncodings;
575
584 public void AddInMemoryChannel()
585 {
586 if (Monitor.Channels.Any(x => x.Name == InMemoryChannelName))
587 {
588 return;
589 }
590
591 Monitor.AddChannel(
593 TransportKind.InMemory,
594 "SampleSmart in-memory communication channel.");
595 }
596
613 public async Task ConnectInMemoryAsync()
614 {
616
617 await _messageBus.ConnectAsync();
618
619 Monitor.UpdateChannelState(
621 ConnectionState.Connected);
622 }
623
640 public async Task DisconnectInMemoryAsync()
641 {
643
644 await _messageBus.DisconnectAsync();
645
646 Monitor.UpdateChannelState(
648 ConnectionState.Disconnected);
649 }
650
675 public async Task SendInMemoryAsync(string text)
676 {
678
679 if (_messageBus.State != ConnectionState.Connected)
680 {
681 await ConnectInMemoryAsync();
682 }
683
684 if (string.IsNullOrWhiteSpace(text))
685 {
686 text = "Hello from SampleSmart InMemory";
687 }
688
689 var message = CreateTextMessage(
690 "Sample.Send",
692 text,
693 "InMemory");
694
695 Monitor.AddSendLog(
697 TransportKind.InMemory,
698 message);
699
700 await _messageBus.PublishAsync(message);
701 }
702
719 public void ReceiveInMemory(string text)
720 {
722
723 if (string.IsNullOrWhiteSpace(text))
724 {
725 text = "Hello from SampleSmart manual receive";
726 }
727
728 var message = CreateTextMessage(
729 "Sample.Receive",
730 "sample.communication.manual-receive",
731 text,
732 "InMemory");
733
734 Monitor.AddReceiveLog(
736 TransportKind.InMemory,
737 message);
738 }
739
788 public async Task StartTcpServerAsync(
789 string protocol,
790 string encodingName = PlainTextProtocolOptions.Utf8EncodingName,
791 string sendTargetMode = nameof(TcpServerSendTargetMode.Broadcast),
792 bool echoEnabled = false)
793 {
794 protocol = NormalizeProtocol(protocol);
795 encodingName = NormalizeTextEncodingName(encodingName);
796 var targetMode = NormalizeTcpServerSendTargetMode(sendTargetMode);
797
798 if (_tcpServer is not null &&
799 _tcpServer.State == ConnectionState.Listening &&
800 _currentServerProtocol == protocol &&
801 _currentServerEncoding == encodingName)
802 {
803 _currentServerSendTargetMode = targetMode;
804 _currentServerEchoEnabled = echoEnabled;
805
806 if (_rawTcpServer is not null)
807 {
808 _rawTcpServer.SendTargetMode = targetMode;
810 protocol,
811 encodingName,
812 _rawTcpServer.ConnectedClientCount,
813 targetMode,
814 echoEnabled);
815 }
816
817 return;
818 }
819
820 if (_tcpServer is not null)
821 {
822 await StopTcpServerAsync();
823 }
824
825 _currentServerProtocol = protocol;
826 _currentServerEncoding = encodingName;
827 _currentServerSendTargetMode = targetMode;
828 _currentServerEchoEnabled = echoEnabled;
829
830 EnsureTcpServerChannel(protocol, encodingName);
831
832 var port = GetTcpPort(protocol);
833
834 _rawTcpServer = new TcpServerTransport(
835 new TcpServerTransportOptions
836 {
837 Host = "127.0.0.1",
838 Port = port,
839 SendTargetMode = targetMode
840 },
842 protocol,
843 "tcp",
844 "Tcp",
845 encodingName),
846 CreateFrameCodec(protocol, encodingName));
847
848 _tcpServer = new ResilientMessageTransport(
852
853 var channelName = GetTcpServerChannelName(protocol, encodingName);
854
857 channelName);
858
861 protocol,
862 encodingName);
863
865 protocol,
866 encodingName,
867 _rawTcpServer.ConnectedClientCount,
868 targetMode,
869 echoEnabled);
870
871 _tcpServer.MessageReceived += OnTcpServerMessageReceived;
872
873 Monitor.UpdateChannelState(channelName, ConnectionState.Connecting);
874
875 await _tcpServer.ConnectAsync();
876
877 Monitor.UpdateChannelState(
878 channelName,
879 _tcpServer.State);
880 }
881
923 string protocol,
924 string encodingName = PlainTextProtocolOptions.Utf8EncodingName,
925 string sendTargetMode = nameof(TcpServerSendTargetMode.Broadcast),
926 bool echoEnabled = false)
927 {
928 protocol = NormalizeProtocol(protocol);
929 encodingName = NormalizeTextEncodingName(encodingName);
930 var targetMode = NormalizeTcpServerSendTargetMode(sendTargetMode);
931
932 _currentServerSendTargetMode = targetMode;
933 _currentServerEchoEnabled = echoEnabled;
934
935 if (_rawTcpServer is null ||
936 _currentServerProtocol != protocol ||
937 _currentServerEncoding != encodingName)
938 {
939 return;
940 }
941
942 _rawTcpServer.SendTargetMode = targetMode;
943
945 protocol,
946 encodingName,
947 _rawTcpServer.ConnectedClientCount,
948 targetMode,
949 echoEnabled);
950 }
951
968 public async Task StopTcpServerAsync()
969 {
970 var protocol = _currentServerProtocol;
971 var encodingName = _currentServerEncoding;
972 var channelName = GetTcpServerChannelName(protocol, encodingName);
973
974 if (_tcpServer is null)
975 {
976 if (Monitor.Channels.Any(x => x.Name == channelName))
977 {
978 Monitor.UpdateChannelState(channelName, ConnectionState.Disconnected);
979 }
980
981 return;
982 }
983
984 _tcpServer.MessageReceived -= OnTcpServerMessageReceived;
985
986 await _tcpServer.DisposeAsync();
987
988 _tcpServer = null;
989 _rawTcpServer = null;
990
991 if (Monitor.Channels.Any(x => x.Name == channelName))
992 {
993 Monitor.UpdateChannelState(channelName, ConnectionState.Disconnected);
994 }
995 }
996
1045 public async Task SendTcpServerAsync(
1046 string protocol,
1047 string text,
1048 string encodingName = PlainTextProtocolOptions.Utf8EncodingName,
1049 string sendTargetMode = nameof(TcpServerSendTargetMode.Broadcast))
1050 {
1051 protocol = NormalizeProtocol(protocol);
1052 encodingName = NormalizeTextEncodingName(encodingName);
1053 var targetMode = NormalizeTcpServerSendTargetMode(sendTargetMode);
1054 _currentServerSendTargetMode = targetMode;
1055
1056 if (_rawTcpServer is not null)
1057 {
1058 _rawTcpServer.SendTargetMode = targetMode;
1060 protocol,
1061 encodingName,
1062 _rawTcpServer.ConnectedClientCount,
1063 targetMode,
1065 }
1066
1067 if (string.IsNullOrWhiteSpace(text))
1068 {
1069 text = "Hello from Dreamine TCP Server";
1070 }
1071
1072 if (_tcpServer is null ||
1073 _tcpServer.State != ConnectionState.Listening ||
1074 _currentServerProtocol != protocol ||
1075 _currentServerEncoding != encodingName)
1076 {
1077 await StartTcpServerAsync(protocol, encodingName, sendTargetMode, _currentServerEchoEnabled);
1078 }
1079
1080 if (_tcpServer is null)
1081 {
1082 return;
1083 }
1084
1085 var message = CreateTcpMessageByProtocol(
1086 protocol,
1087 $"Server.Send.{targetMode}",
1088 text,
1089 encodingName);
1090
1091 var channelName = GetTcpServerChannelName(protocol, encodingName);
1092
1093 Monitor.AddSendLog(
1094 channelName,
1095 TransportKind.Tcp,
1096 message);
1097
1098 await _tcpServer.SendAsync(message);
1099 }
1100
1133 public async Task ConnectTcpClientAsync(
1134 string protocol,
1135 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
1136 {
1137 protocol = NormalizeProtocol(protocol);
1138 encodingName = NormalizeTextEncodingName(encodingName);
1139
1140 if (_tcpClient is not null &&
1141 _tcpClient.State == ConnectionState.Connected &&
1142 _currentClientProtocol == protocol &&
1143 _currentClientEncoding == encodingName)
1144 {
1145 return;
1146 }
1147
1148 await PrepareTcpClientTransportAsync(protocol, encodingName);
1149
1150 if (_tcpClient is null)
1151 {
1152 return;
1153 }
1154
1155 var channelName = GetTcpClientChannelName(protocol, encodingName);
1156
1157 Monitor.UpdateChannelState(channelName, ConnectionState.Connecting);
1158
1159 try
1160 {
1161 await _tcpClient.ConnectAsync();
1162
1163 Monitor.UpdateChannelState(
1164 channelName,
1165 _tcpClient.State);
1166 }
1167 catch
1168 {
1169 // ResilientMessageTransport의 내부 WatchLoop가 계속 재연결을 시도합니다.
1170 // 수동 Connect 실패는 UI 상태만 Connecting으로 유지하고 예외를 샘플 밖으로 전파하지 않습니다.
1171 Monitor.UpdateChannelState(channelName, ConnectionState.Connecting);
1172 }
1173 }
1174
1208 string protocol,
1209 string encodingName)
1210 {
1211 protocol = NormalizeProtocol(protocol);
1212 encodingName = NormalizeTextEncodingName(encodingName);
1213
1214 if (_tcpClient is not null &&
1215 _currentClientProtocol == protocol &&
1216 _currentClientEncoding == encodingName)
1217 {
1218 return;
1219 }
1220
1221 if (_tcpClient is not null)
1222 {
1224 }
1225
1226 _currentClientProtocol = protocol;
1227 _currentClientEncoding = encodingName;
1228
1229 EnsureTcpClientChannel(protocol, encodingName);
1230
1231 var port = GetTcpPort(protocol);
1232
1233 var rawTcpClient = new TcpClientTransport(
1234 new TcpClientTransportOptions
1235 {
1236 Host = "127.0.0.1",
1237 Port = port
1238 },
1240 protocol,
1241 "tcp",
1242 "Tcp",
1243 encodingName),
1244 CreateFrameCodec(protocol, encodingName));
1245
1246 _tcpClient = new ResilientMessageTransport(
1247 rawTcpClient,
1250
1251 var channelName = GetTcpClientChannelName(protocol, encodingName);
1252
1254 _tcpClient,
1255 channelName);
1256
1258 _tcpClient,
1259 protocol,
1260 encodingName,
1261 channelName);
1262
1263 _tcpClient.MessageReceived += OnTcpClientMessageReceived;
1264
1265 Monitor.UpdateChannelState(
1266 channelName,
1267 _tcpClient.State);
1268 }
1269
1286 public async Task DisconnectTcpClientAsync()
1287 {
1288 var protocol = _currentClientProtocol;
1289 var encodingName = _currentClientEncoding;
1290 var channelName = GetTcpClientChannelName(protocol, encodingName);
1291
1292 if (_tcpClient is null)
1293 {
1294 if (Monitor.Channels.Any(x => x.Name == channelName))
1295 {
1296 Monitor.UpdateChannelState(channelName, ConnectionState.Disconnected);
1297 }
1298
1299 return;
1300 }
1301
1302 _tcpClient.MessageReceived -= OnTcpClientMessageReceived;
1303
1304 await _tcpClient.DisposeAsync();
1305
1306 _tcpClient = null;
1307
1308 if (Monitor.Channels.Any(x => x.Name == channelName))
1309 {
1310 Monitor.UpdateChannelState(channelName, ConnectionState.Disconnected);
1311 }
1312 }
1313
1354 public async Task SendTcpClientAsync(
1355 string protocol,
1356 string text,
1357 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
1358 {
1359 protocol = NormalizeProtocol(protocol);
1360 encodingName = NormalizeTextEncodingName(encodingName);
1361
1362 if (string.IsNullOrWhiteSpace(text))
1363 {
1364 text = "Hello from Dreamine TCP Client";
1365 }
1366
1367 await PrepareTcpClientTransportAsync(protocol, encodingName);
1368
1369 if (_tcpClient is null)
1370 {
1371 return;
1372 }
1373
1374 var message = CreateTcpMessageByProtocol(
1375 protocol,
1376 "Client.Send",
1377 text,
1378 encodingName);
1379
1380 var channelName = GetTcpClientChannelName(protocol, encodingName);
1381
1382 Monitor.AddSendLog(
1383 channelName,
1384 TransportKind.Tcp,
1385 message);
1386
1387 await _tcpClient.SendAsync(message);
1388
1389 if (_tcpClient is ResilientMessageTransport resilientTransport)
1390 {
1391 var queueStatusMessage = CreateTcpMessageByProtocol(
1392 protocol,
1393 "Client.QueueStatus",
1394 $"QueueCount={resilientTransport.QueuedMessageCount}, State={_tcpClient.State}",
1395 encodingName);
1396
1397 Monitor.AddReceiveLog(
1398 channelName,
1399 TransportKind.Tcp,
1400 queueStatusMessage);
1401 }
1402
1403 Monitor.UpdateChannelState(
1404 channelName,
1405 _tcpClient.State);
1406 }
1407
1424 public async Task StopAllTcpAsync()
1425 {
1427 await StopTcpServerAsync();
1428 }
1429
1462 public async Task StartUdpLoopbackAsync(
1463 string protocol,
1464 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
1465 {
1466 await ConnectUdpPeerAAsync(protocol, encodingName);
1467 await ConnectUdpPeerBAsync(protocol, encodingName);
1468 }
1469
1502 public async Task ConnectUdpPeerAAsync(
1503 string protocol,
1504 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
1505 {
1506 protocol = NormalizeProtocol(protocol);
1507 encodingName = NormalizeTextEncodingName(encodingName);
1508
1509 if (_udpPeerA is not null &&
1510 _udpPeerA.State == ConnectionState.Connected &&
1511 _currentUdpPeerAProtocol == protocol &&
1512 _currentUdpPeerAEncoding == encodingName)
1513 {
1514 return;
1515 }
1516
1517 if (_udpPeerA is not null)
1518 {
1520 }
1521
1522 _currentUdpPeerAProtocol = protocol;
1523 _currentUdpPeerAEncoding = encodingName;
1524
1525 EnsureUdpPeerChannel("A", protocol, encodingName);
1526
1527 _udpPeerA = new UdpTransport(
1528 new UdpTransportOptions
1529 {
1530 LocalHost = "127.0.0.1",
1531 LocalPort = UdpPeerALocalPort,
1532 RemoteHost = "127.0.0.1",
1533 RemotePort = UdpPeerBLocalPort,
1534 ReuseAddress = true
1535 },
1537 protocol,
1538 "udp",
1539 "Udp",
1540 encodingName));
1541
1542 _udpPeerA.MessageReceived += OnUdpPeerAMessageReceived;
1543
1544 await _udpPeerA.ConnectAsync();
1545
1546 Monitor.UpdateChannelState(
1547 GetUdpPeerChannelName("A", protocol, encodingName),
1548 ConnectionState.Connected);
1549 }
1550
1583 public async Task ConnectUdpPeerBAsync(
1584 string protocol,
1585 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
1586 {
1587 protocol = NormalizeProtocol(protocol);
1588 encodingName = NormalizeTextEncodingName(encodingName);
1589
1590 if (_udpPeerB is not null &&
1591 _udpPeerB.State == ConnectionState.Connected &&
1592 _currentUdpPeerBProtocol == protocol &&
1593 _currentUdpPeerBEncoding == encodingName)
1594 {
1595 return;
1596 }
1597
1598 if (_udpPeerB is not null)
1599 {
1601 }
1602
1603 _currentUdpPeerBProtocol = protocol;
1604 _currentUdpPeerBEncoding = encodingName;
1605
1606 EnsureUdpPeerChannel("B", protocol, encodingName);
1607
1608 _udpPeerB = new UdpTransport(
1609 new UdpTransportOptions
1610 {
1611 LocalHost = "127.0.0.1",
1612 LocalPort = UdpPeerBLocalPort,
1613 RemoteHost = "127.0.0.1",
1614 RemotePort = UdpPeerALocalPort,
1615 ReuseAddress = true
1616 },
1618 protocol,
1619 "udp",
1620 "Udp",
1621 encodingName));
1622
1623 _udpPeerB.MessageReceived += OnUdpPeerBMessageReceived;
1624
1625 await _udpPeerB.ConnectAsync();
1626
1627 Monitor.UpdateChannelState(
1628 GetUdpPeerChannelName("B", protocol, encodingName),
1629 ConnectionState.Connected);
1630 }
1631
1648 public async Task DisconnectUdpPeerAAsync()
1649 {
1650 var protocol = _currentUdpPeerAProtocol;
1651 var encodingName = _currentUdpPeerAEncoding;
1652 var channelName = GetUdpPeerChannelName("A", protocol, encodingName);
1653
1654 if (_udpPeerA is null)
1655 {
1656 if (Monitor.Channels.Any(x => x.Name == channelName))
1657 {
1658 Monitor.UpdateChannelState(channelName, ConnectionState.Disconnected);
1659 }
1660
1661 return;
1662 }
1663
1664 _udpPeerA.MessageReceived -= OnUdpPeerAMessageReceived;
1665
1666 await _udpPeerA.DisposeAsync();
1667
1668 _udpPeerA = null;
1669
1670 if (Monitor.Channels.Any(x => x.Name == channelName))
1671 {
1672 Monitor.UpdateChannelState(channelName, ConnectionState.Disconnected);
1673 }
1674 }
1675
1692 public async Task DisconnectUdpPeerBAsync()
1693 {
1694 var protocol = _currentUdpPeerBProtocol;
1695 var encodingName = _currentUdpPeerBEncoding;
1696 var channelName = GetUdpPeerChannelName("B", protocol, encodingName);
1697
1698 if (_udpPeerB is null)
1699 {
1700 if (Monitor.Channels.Any(x => x.Name == channelName))
1701 {
1702 Monitor.UpdateChannelState(channelName, ConnectionState.Disconnected);
1703 }
1704
1705 return;
1706 }
1707
1708 _udpPeerB.MessageReceived -= OnUdpPeerBMessageReceived;
1709
1710 await _udpPeerB.DisposeAsync();
1711
1712 _udpPeerB = null;
1713
1714 if (Monitor.Channels.Any(x => x.Name == channelName))
1715 {
1716 Monitor.UpdateChannelState(channelName, ConnectionState.Disconnected);
1717 }
1718 }
1719
1736 public async Task StopAllUdpAsync()
1737 {
1740 }
1741
1782 public async Task SendUdpPeerAAsync(
1783 string protocol,
1784 string text,
1785 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
1786 {
1787 protocol = NormalizeProtocol(protocol);
1788 encodingName = NormalizeTextEncodingName(encodingName);
1789
1790 if (string.IsNullOrWhiteSpace(text))
1791 {
1792 text = "Hello from Dreamine UDP Peer A";
1793 }
1794
1795 if (_udpPeerA is null ||
1796 _udpPeerA.State != ConnectionState.Connected ||
1797 _currentUdpPeerAProtocol != protocol ||
1798 _currentUdpPeerAEncoding != encodingName)
1799 {
1800 await ConnectUdpPeerAAsync(protocol, encodingName);
1801 }
1802
1803 if (_udpPeerA is null)
1804 {
1805 return;
1806 }
1807
1808 var message = CreateUdpMessageByProtocol(
1809 protocol,
1810 "PeerA.Send",
1811 text,
1812 encodingName);
1813
1814 var channelName = GetUdpPeerChannelName("A", protocol, encodingName);
1815
1816 Monitor.AddSendLog(
1817 channelName,
1818 TransportKind.Udp,
1819 message);
1820
1821 await _udpPeerA.SendAsync(message);
1822 }
1823
1864 public async Task SendUdpPeerBAsync(
1865 string protocol,
1866 string text,
1867 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
1868 {
1869 protocol = NormalizeProtocol(protocol);
1870 encodingName = NormalizeTextEncodingName(encodingName);
1871
1872 if (string.IsNullOrWhiteSpace(text))
1873 {
1874 text = "Hello from Dreamine UDP Peer B";
1875 }
1876
1877 if (_udpPeerB is null ||
1878 _udpPeerB.State != ConnectionState.Connected ||
1879 _currentUdpPeerBProtocol != protocol ||
1880 _currentUdpPeerBEncoding != encodingName)
1881 {
1882 await ConnectUdpPeerBAsync(protocol, encodingName);
1883 }
1884
1885 if (_udpPeerB is null)
1886 {
1887 return;
1888 }
1889
1890 var message = CreateUdpMessageByProtocol(
1891 protocol,
1892 "PeerB.Send",
1893 text,
1894 encodingName);
1895
1896 var channelName = GetUdpPeerChannelName("B", protocol, encodingName);
1897
1898 Monitor.AddSendLog(
1899 channelName,
1900 TransportKind.Udp,
1901 message);
1902
1903 await _udpPeerB.SendAsync(message);
1904 }
1905
1954 public async Task ConnectSerialAsync(
1955 string portName,
1956 int baudRate,
1957 string protocol,
1958 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
1959 {
1960 if (string.IsNullOrWhiteSpace(portName))
1961 {
1962 return;
1963 }
1964
1965 protocol = NormalizeProtocol(protocol);
1966 encodingName = NormalizeTextEncodingName(encodingName);
1967
1968 if (_serialTransport is not null &&
1969 _serialTransport.State == ConnectionState.Connected &&
1970 _currentSerialPortName == portName &&
1971 _currentSerialBaudRate == baudRate &&
1972 _currentSerialProtocol == protocol &&
1973 _currentSerialEncoding == encodingName)
1974 {
1975 return;
1976 }
1977
1978 if (_serialTransport is not null)
1979 {
1980 await DisconnectSerialAsync();
1981 }
1982
1983 _currentSerialPortName = portName;
1984 _currentSerialBaudRate = baudRate;
1985 _currentSerialProtocol = protocol;
1986 _currentSerialEncoding = encodingName;
1987
1989
1990 _serialTransport = new SerialPortTransport(
1991 new SerialPortTransportOptions
1992 {
1993 PortName = portName,
1994 BaudRate = baudRate
1995 },
1997 protocol,
1998 "serial",
1999 "Serial",
2000 encodingName),
2001 CreateFrameCodec(protocol, encodingName));
2002
2003 _serialTransport.MessageReceived += OnSerialMessageReceived;
2004
2005 await _serialTransport.ConnectAsync();
2006
2007 Monitor.UpdateChannelState(
2009 ConnectionState.Connected);
2010 }
2011
2028 public async Task DisconnectSerialAsync()
2029 {
2030 var channelName = GetSerialChannelName();
2031
2032 if (_serialTransport is null)
2033 {
2034 if (Monitor.Channels.Any(x => x.Name == channelName))
2035 {
2036 Monitor.UpdateChannelState(channelName, ConnectionState.Disconnected);
2037 }
2038
2039 return;
2040 }
2041
2042 _serialTransport.MessageReceived -= OnSerialMessageReceived;
2043
2044 await _serialTransport.DisposeAsync();
2045
2046 _serialTransport = null;
2047
2048 if (Monitor.Channels.Any(x => x.Name == channelName))
2049 {
2050 Monitor.UpdateChannelState(channelName, ConnectionState.Disconnected);
2051 }
2052 }
2053
2094 public async Task SendSerialAsync(
2095 string protocol,
2096 string text,
2097 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
2098 {
2099 protocol = NormalizeProtocol(protocol);
2100 encodingName = NormalizeTextEncodingName(encodingName);
2101
2102 if (string.IsNullOrWhiteSpace(text))
2103 {
2104 text = "test";
2105 }
2106
2107 if (_serialTransport is null ||
2108 _serialTransport.State != ConnectionState.Connected)
2109 {
2110 return;
2111 }
2112
2113 var message = CreateSerialMessageByProtocol(
2114 protocol,
2115 "Send",
2116 text,
2117 encodingName);
2118
2119 var channelName = GetSerialChannelName();
2120
2121 Monitor.AddSendLog(
2122 channelName,
2123 TransportKind.Serial,
2124 message);
2125
2126 await _serialTransport.SendAsync(message);
2127 }
2128
2209 public async Task ConnectRabbitMqAsync(
2210 string host,
2211 int port,
2212 string virtualHost,
2213 string userName,
2214 string password,
2215 string exchangeName,
2216 string queueName,
2217 string routingKey)
2218 {
2219 host = NormalizeText(host, "localhost");
2220 virtualHost = NormalizeText(virtualHost, "/");
2221 userName = NormalizeText(userName, "guest");
2222 password = NormalizeText(password, "guest");
2223 exchangeName = NormalizeText(exchangeName, "dreamine.sample.exchange");
2224 queueName = NormalizeText(queueName, "dreamine.sample.queue");
2225 routingKey = NormalizeText(routingKey, "dreamine.sample.route");
2226
2227 if (port <= 0 || port > 65535)
2228 {
2229 port = 5672;
2230 }
2231
2232 if (_rabbitMqBus is not null &&
2233 _rabbitMqBus.State == ConnectionState.Connected &&
2234 _currentRabbitMqHost == host &&
2235 _currentRabbitMqPort == port &&
2236 _currentRabbitMqVirtualHost == virtualHost &&
2237 _currentRabbitMqExchangeName == exchangeName &&
2238 _currentRabbitMqQueueName == queueName &&
2239 _currentRabbitMqRoutingKey == routingKey)
2240 {
2241 return;
2242 }
2243
2244 if (_rabbitMqBus is not null)
2245 {
2247 }
2248
2249 _currentRabbitMqHost = host;
2250 _currentRabbitMqPort = port;
2251 _currentRabbitMqVirtualHost = virtualHost;
2252 _currentRabbitMqExchangeName = exchangeName;
2253 _currentRabbitMqQueueName = queueName;
2254 _currentRabbitMqRoutingKey = routingKey;
2255 _isRabbitMqSubscribed = false;
2256
2258
2259 _rabbitMqBus = new RabbitMqMessageBus(
2260 new RabbitMqMessageBusOptions
2261 {
2262 HostName = host,
2263 Port = port,
2264 VirtualHost = virtualHost,
2265 UserName = userName,
2266 Password = password,
2267 ExchangeName = exchangeName,
2268 QueueName = queueName,
2269 RoutingKey = routingKey
2270 });
2271
2272 try
2273 {
2274 await _rabbitMqBus.ConnectAsync();
2275
2276 Monitor.UpdateChannelState(
2278 ConnectionState.Connected);
2279 }
2280 catch (Exception ex)
2281 {
2282 Monitor.UpdateChannelState(
2284 ConnectionState.Faulted);
2285
2286 AddRabbitMqErrorLog("RabbitMQ.Connect.Failed", ex.Message);
2287 }
2288 }
2289
2330 public async Task SubscribeRabbitMqAsync(
2331 string exchangeName,
2332 string queueName,
2333 string routingKey)
2334 {
2335 exchangeName = NormalizeText(exchangeName, _currentRabbitMqExchangeName);
2336 queueName = NormalizeText(queueName, _currentRabbitMqQueueName);
2337 routingKey = NormalizeText(routingKey, _currentRabbitMqRoutingKey);
2338
2339 if (_rabbitMqBus is null)
2340 {
2342 "RabbitMQ.Subscribe.Skipped",
2343 "RabbitMQ is not connected.");
2344 return;
2345 }
2346
2347 if (_rabbitMqBus.State != ConnectionState.Connected)
2348 {
2350 "RabbitMQ.Subscribe.Skipped",
2351 $"RabbitMQ state is {_rabbitMqBus.State}.");
2352 return;
2353 }
2354
2356 {
2357 return;
2358 }
2359
2360 _currentRabbitMqExchangeName = exchangeName;
2361 _currentRabbitMqQueueName = queueName;
2362 _currentRabbitMqRoutingKey = routingKey;
2363
2364 try
2365 {
2366 await _rabbitMqBus.SubscribeAsync(
2367 routingKey,
2368 (message, _) =>
2369 {
2370 RunOnUiThread(() =>
2371 {
2372 Monitor.AddReceiveLog(
2374 TransportKind.RabbitMq,
2375 message);
2376 });
2377
2378 return Task.CompletedTask;
2379 });
2380
2381 _isRabbitMqSubscribed = true;
2382 }
2383 catch (Exception ex)
2384 {
2385 AddRabbitMqErrorLog("RabbitMQ.Subscribe.Failed", ex.Message);
2386 }
2387 }
2388
2429 public async Task PublishRabbitMqAsync(
2430 string exchangeName,
2431 string routingKey,
2432 string text)
2433 {
2434 exchangeName = NormalizeText(exchangeName, _currentRabbitMqExchangeName);
2435 routingKey = NormalizeText(routingKey, _currentRabbitMqRoutingKey);
2436
2437 if (string.IsNullOrWhiteSpace(text))
2438 {
2439 text = "test";
2440 }
2441
2442 if (_rabbitMqBus is null)
2443 {
2445 "RabbitMQ.Publish.Skipped",
2446 "RabbitMQ is not connected.");
2447 return;
2448 }
2449
2450 if (_rabbitMqBus.State != ConnectionState.Connected)
2451 {
2453 "RabbitMQ.Publish.Skipped",
2454 $"RabbitMQ state is {_rabbitMqBus.State}.");
2455 return;
2456 }
2457
2458 _currentRabbitMqExchangeName = exchangeName;
2459 _currentRabbitMqRoutingKey = routingKey;
2460
2461 var message = CreateRabbitMqMessage(
2462 "Publish",
2463 routingKey,
2464 text);
2465
2466 Monitor.AddSendLog(
2468 TransportKind.RabbitMq,
2469 message);
2470
2471 try
2472 {
2473 await _rabbitMqBus.PublishAsync(message);
2474 }
2475 catch (Exception ex)
2476 {
2477 AddRabbitMqErrorLog("RabbitMQ.Publish.Failed", ex.Message);
2478 }
2479 }
2480
2497 public async Task DisconnectRabbitMqAsync()
2498 {
2499 if (_rabbitMqBus is null)
2500 {
2501 if (Monitor.Channels.Any(x => x.Name == RabbitMqChannelName))
2502 {
2503 Monitor.UpdateChannelState(
2505 ConnectionState.Disconnected);
2506 }
2507
2508 return;
2509 }
2510
2511 await _rabbitMqBus.DisposeAsync();
2512
2513 _rabbitMqBus = null;
2514 _isRabbitMqSubscribed = false;
2515
2516 if (Monitor.Channels.Any(x => x.Name == RabbitMqChannelName))
2517 {
2518 Monitor.UpdateChannelState(
2520 ConnectionState.Disconnected);
2521 }
2522 }
2523
2540 public async Task StopAllAsync()
2541 {
2543 await DisconnectSerialAsync();
2544 await StopAllUdpAsync();
2545 await StopAllTcpAsync();
2547 }
2548
2565 private async Task SubscribeInMemoryAsync()
2566 {
2568 {
2569 return;
2570 }
2571
2572 _isInMemorySubscribed = true;
2573
2574 await _messageBus.SubscribeAsync(
2576 (message, _) =>
2577 {
2578 RunOnUiThread(() =>
2579 {
2580 Monitor.AddReceiveLog(
2582 TransportKind.InMemory,
2583 message);
2584 });
2585
2586 return Task.CompletedTask;
2587 });
2588 }
2589
2614 private async void OnTcpServerMessageReceived(object? sender, MessageEnvelope message)
2615 {
2616 var protocol = _currentServerProtocol;
2617 var encodingName = _currentServerEncoding;
2618 var channelName = GetTcpServerChannelName(protocol, encodingName);
2619
2620 RunOnUiThread(() =>
2621 {
2622 Monitor.AddReceiveLog(
2623 channelName,
2624 TransportKind.Tcp,
2625 message);
2626 });
2627
2628 if (_tcpServer is null ||
2629 _tcpServer.State != ConnectionState.Listening ||
2631 {
2632 return;
2633 }
2634
2635 var receiveText = Encoding.UTF8.GetString(message.Payload);
2636
2637 var echoMessage = CreateTcpMessageByProtocol(
2638 protocol,
2639 $"Server.Echo.{_currentServerSendTargetMode}",
2640 $"Echo from Dreamine TCP Server - {receiveText}",
2641 encodingName);
2642
2643 RunOnUiThread(() =>
2644 {
2645 Monitor.AddSendLog(
2646 channelName,
2647 TransportKind.Tcp,
2648 echoMessage);
2649 });
2650
2651 await _tcpServer.SendAsync(echoMessage);
2652 }
2653
2670 private static ReconnectPolicy CreateSampleReconnectPolicy()
2671 {
2672 return new ReconnectPolicy
2673 {
2674 Enabled = true,
2675 InitialDelay = TimeSpan.FromSeconds(1),
2676 MaxDelay = TimeSpan.FromSeconds(5),
2677 BackoffFactor = 1.5,
2678 MaxRetryCount = null,
2679 WatchInterval = TimeSpan.FromMilliseconds(500)
2680 };
2681 }
2682
2699 private static OutboundQueueOptions CreateSampleOutboundQueueOptions()
2700 {
2701 return new OutboundQueueOptions
2702 {
2703 DisconnectedSendPolicy = DisconnectedSendPolicy.Queue,
2704 MaxQueueSize = 10_000,
2705 DropOldestWhenFull = true,
2706 MaxMessageAge = null,
2707 FlushOnReconnect = true
2708 };
2709 }
2710
2727 private static OutboundQueueOptions CreateSampleServerOutboundQueueOptions()
2728 {
2729 return new OutboundQueueOptions
2730 {
2731 DisconnectedSendPolicy = DisconnectedSendPolicy.Fail,
2732 MaxQueueSize = 1_000,
2733 DropOldestWhenFull = true,
2734 MaxMessageAge = null,
2735 FlushOnReconnect = false
2736 };
2737 }
2738
2764 IMessageTransport transport,
2765 string channelName)
2766 {
2767 if (transport is not ResilientMessageTransport resilientTransport)
2768 {
2769 return;
2770 }
2771
2772 resilientTransport.StateChanged += (_, state) =>
2773 {
2774 RunOnUiThread(() =>
2775 {
2776 Monitor.UpdateChannelState(
2777 channelName,
2778 state);
2779 });
2780 };
2781 }
2782
2816 TcpServerTransport tcpServerTransport,
2817 string protocol,
2818 string encodingName)
2819 {
2820 tcpServerTransport.ConnectedClientCountChanged += (_, clientCount) =>
2821 {
2822 RunOnUiThread(() =>
2823 {
2825 protocol,
2826 encodingName,
2827 clientCount,
2830 });
2831 };
2832 }
2833
2883 string protocol,
2884 string encodingName,
2885 int clientCount,
2886 TcpServerSendTargetMode targetMode,
2887 bool echoEnabled)
2888 {
2889 var channelName = GetTcpServerChannelName(protocol, encodingName);
2890 var port = GetTcpPort(protocol);
2891
2892 Monitor.UpdateChannelDescription(
2893 channelName,
2894 CreateTcpServerDescription(protocol, encodingName, port, clientCount, targetMode, echoEnabled));
2895 }
2896
2961 private static string CreateTcpServerDescription(
2962 string protocol,
2963 string encodingName,
2964 int port,
2965 int clientCount,
2966 TcpServerSendTargetMode targetMode,
2967 bool echoEnabled)
2968 {
2969 var echoText = echoEnabled ? "On" : "Off";
2970
2971 return $"TCP server [{protocol}/{NormalizeTextEncodingName(encodingName)}] on 127.0.0.1:{port}. Clients={clientCount}. Target={targetMode}. Echo={echoText}.";
2972 }
2973
3015 IMessageTransport transport,
3016 string protocol,
3017 string encodingName,
3018 string channelName)
3019 {
3020 if (transport is not ResilientMessageTransport resilientTransport)
3021 {
3022 return;
3023 }
3024
3025 resilientTransport.QueueCountChanged += (_, queueCount) =>
3026 {
3027 var queueStatusMessage = CreateTcpMessageByProtocol(
3028 protocol,
3029 "Client.QueueStatus",
3030 $"QueueCount={queueCount}, State={resilientTransport.State}",
3031 encodingName);
3032
3033 RunOnUiThread(() =>
3034 {
3035 Monitor.AddReceiveLog(
3036 channelName,
3037 TransportKind.Tcp,
3038 queueStatusMessage);
3039
3040 Monitor.UpdateChannelState(
3041 channelName,
3042 resilientTransport.State);
3043 });
3044 };
3045 }
3046
3071 private void OnTcpClientMessageReceived(object? sender, MessageEnvelope message)
3072 {
3073 var protocol = _currentClientProtocol;
3074 var encodingName = _currentClientEncoding;
3075 var channelName = GetTcpClientChannelName(protocol, encodingName);
3076
3077 RunOnUiThread(() =>
3078 {
3079 Monitor.AddReceiveLog(
3080 channelName,
3081 TransportKind.Tcp,
3082 message);
3083 });
3084 }
3085
3110 private void OnUdpPeerAMessageReceived(object? sender, MessageEnvelope message)
3111 {
3112 var protocol = _currentUdpPeerAProtocol;
3113 var encodingName = _currentUdpPeerAEncoding;
3114 var channelName = GetUdpPeerChannelName("A", protocol, encodingName);
3115
3116 RunOnUiThread(() =>
3117 {
3118 Monitor.AddReceiveLog(
3119 channelName,
3120 TransportKind.Udp,
3121 message);
3122 });
3123 }
3124
3149 private void OnUdpPeerBMessageReceived(object? sender, MessageEnvelope message)
3150 {
3151 var protocol = _currentUdpPeerBProtocol;
3152 var encodingName = _currentUdpPeerBEncoding;
3153 var channelName = GetUdpPeerChannelName("B", protocol, encodingName);
3154
3155 RunOnUiThread(() =>
3156 {
3157 Monitor.AddReceiveLog(
3158 channelName,
3159 TransportKind.Udp,
3160 message);
3161 });
3162 }
3163
3188 private void OnSerialMessageReceived(object? sender, MessageEnvelope message)
3189 {
3190 var channelName = GetSerialChannelName();
3191
3192 RunOnUiThread(() =>
3193 {
3194 Monitor.AddReceiveLog(
3195 channelName,
3196 TransportKind.Serial,
3197 message);
3198 });
3199 }
3200
3226 string protocol,
3227 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
3228 {
3229 var channelName = GetTcpServerChannelName(protocol, encodingName);
3230 var port = GetTcpPort(protocol);
3231
3232 if (Monitor.Channels.Any(x => x.Name == channelName))
3233 {
3234 return;
3235 }
3236
3237 Monitor.AddChannel(
3238 channelName,
3239 TransportKind.Tcp,
3241 protocol,
3242 encodingName,
3243 port,
3244 0,
3247 }
3248
3274 string protocol,
3275 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
3276 {
3277 var channelName = GetTcpClientChannelName(protocol, encodingName);
3278 var port = GetTcpPort(protocol);
3279
3280 if (Monitor.Channels.Any(x => x.Name == channelName))
3281 {
3282 return;
3283 }
3284
3285 Monitor.AddChannel(
3286 channelName,
3287 TransportKind.Tcp,
3288 $"TCP client [{protocol}/{NormalizeTextEncodingName(encodingName)}] to 127.0.0.1:{port}.");
3289 }
3290
3324 string peerName,
3325 string protocol,
3326 string encodingName)
3327 {
3328 encodingName = NormalizeTextEncodingName(encodingName);
3329
3330 var channelName = GetUdpPeerChannelName(peerName, protocol, encodingName);
3331 var localPort = GetUdpLocalPort(peerName);
3332 var remotePort = GetUdpRemotePort(peerName);
3333
3334 if (Monitor.Channels.Any(x => x.Name == channelName))
3335 {
3336 return;
3337 }
3338
3339 Monitor.AddChannel(
3340 channelName,
3341 TransportKind.Udp,
3342 $"UDP peer {peerName} [{protocol}/{encodingName}] 127.0.0.1:{localPort} -> 127.0.0.1:{remotePort}.");
3343 }
3344
3353 private void EnsureSerialChannel()
3354 {
3355 var channelName = GetSerialChannelName();
3356
3357 if (Monitor.Channels.Any(x => x.Name == channelName))
3358 {
3359 return;
3360 }
3361
3362 Monitor.AddChannel(
3363 channelName,
3364 TransportKind.Serial,
3365 $"Serial [{_currentSerialProtocol}/{_currentSerialEncoding}] on {_currentSerialPortName}:{_currentSerialBaudRate}.");
3366 }
3367
3377 {
3378 if (Monitor.Channels.Any(x => x.Name == RabbitMqChannelName))
3379 {
3380 return;
3381 }
3382
3383 Monitor.AddChannel(
3385 TransportKind.RabbitMq,
3386 $"RabbitMQ on {_currentRabbitMqHost}:{_currentRabbitMqPort}, vhost={_currentRabbitMqVirtualHost}, exchange={_currentRabbitMqExchangeName}, queue={_currentRabbitMqQueueName}, route={_currentRabbitMqRoutingKey}.");
3387 }
3388
3405 private string GetSerialChannelName()
3406 {
3407 if (string.IsNullOrWhiteSpace(_currentSerialPortName))
3408 {
3409 return "Serial-Port";
3410 }
3411
3412 return $"Serial-{_currentSerialPortName}";
3413 }
3414
3463 private static IMessageProtocolAdapter CreateProtocolAdapter(
3464 string protocol,
3465 string routePrefix = "tcp",
3466 string namePrefix = "Tcp",
3467 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
3468 {
3469 var normalizedProtocol = NormalizeProtocol(protocol);
3470 var textEncoding = PlainTextProtocolOptions.CreateEncoding(encodingName);
3471
3472 return normalizedProtocol switch
3473 {
3474 DreamineEnvelopeProtocol => new DreamineEnvelopeProtocolAdapter(),
3475
3476 PlainTextProtocol => new PlainTextProtocolAdapter(
3477 textEncoding,
3478 $"{routePrefix}.plaintext",
3479 $"{namePrefix}.PlainText"),
3480
3481 RawAvailableProtocol => new PlainTextProtocolAdapter(
3482 textEncoding,
3483 $"{routePrefix}.raw.available",
3484 $"{namePrefix}.RawAvailable"),
3485
3486 RawJsonProtocol => new RawJsonProtocolAdapter(
3487 textEncoding,
3488 $"{routePrefix}.rawjson",
3489 $"{namePrefix}.RawJson"),
3490
3491 _ => new PlainTextProtocolAdapter(
3492 textEncoding,
3493 $"{routePrefix}.plaintext",
3494 $"{namePrefix}.PlainText")
3495 };
3496 }
3497
3530 private static IMessageFrameCodec CreateFrameCodec(
3531 string protocol,
3532 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
3533 {
3534 var delimiterEncoding = PlainTextProtocolOptions.CreateEncoding(encodingName);
3535
3536 return NormalizeProtocol(protocol) switch
3537 {
3538 DreamineEnvelopeProtocol => new LengthPrefixedMessageFrameCodec(),
3539
3540 PlainTextProtocol => new DelimiterMessageFrameCodec(
3541 "\r\n",
3542 delimiterEncoding,
3543 1024 * 1024),
3544
3545 RawAvailableProtocol => new RawAvailableMessageFrameCodec(),
3546
3547 RawJsonProtocol => new DelimiterMessageFrameCodec(
3548 "\r\n",
3549 Encoding.UTF8,
3550 1024 * 1024),
3551
3552 _ => new DelimiterMessageFrameCodec(
3553 "\r\n",
3554 delimiterEncoding,
3555 1024 * 1024)
3556 };
3557 }
3558
3583 private static int GetTcpPort(string protocol)
3584 {
3585 return NormalizeProtocol(protocol) switch
3586 {
3592 };
3593 }
3594
3627 private static string GetTcpServerChannelName(
3628 string protocol,
3629 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
3630 {
3631 var normalizedEncodingName = NormalizeTextEncodingName(encodingName);
3632
3633 return NormalizeProtocol(protocol) switch
3634 {
3635 DreamineEnvelopeProtocol => "TCP-Server-Dreamine",
3636 PlainTextProtocol => $"TCP-Server-PlainText-{normalizedEncodingName}",
3637 RawAvailableProtocol => $"TCP-Server-RawAvailable-{normalizedEncodingName}",
3638 RawJsonProtocol => "TCP-Server-RawJson",
3639 _ => $"TCP-Server-PlainText-{normalizedEncodingName}"
3640 };
3641 }
3642
3675 private static string GetTcpClientChannelName(
3676 string protocol,
3677 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
3678 {
3679 var normalizedEncodingName = NormalizeTextEncodingName(encodingName);
3680
3681 return NormalizeProtocol(protocol) switch
3682 {
3683 DreamineEnvelopeProtocol => "TCP-Client-Dreamine",
3684 PlainTextProtocol => $"TCP-Client-PlainText-{normalizedEncodingName}",
3685 RawAvailableProtocol => $"TCP-Client-RawAvailable-{normalizedEncodingName}",
3686 RawJsonProtocol => "TCP-Client-RawJson",
3687 _ => $"TCP-Client-PlainText-{normalizedEncodingName}"
3688 };
3689 }
3690
3731 private static string GetUdpPeerChannelName(
3732 string peerName,
3733 string protocol,
3734 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
3735 {
3736 var normalizedPeerName = NormalizeUdpPeerName(peerName);
3737 var normalizedEncodingName = NormalizeTextEncodingName(encodingName);
3738
3739 return NormalizeProtocol(protocol) switch
3740 {
3741 DreamineEnvelopeProtocol => $"UDP-Peer{normalizedPeerName}-Dreamine",
3742 PlainTextProtocol => $"UDP-Peer{normalizedPeerName}-PlainText-{normalizedEncodingName}",
3743 RawAvailableProtocol => $"UDP-Peer{normalizedPeerName}-RawAvailable-{normalizedEncodingName}",
3744 RawJsonProtocol => $"UDP-Peer{normalizedPeerName}-RawJson",
3745 _ => $"UDP-Peer{normalizedPeerName}-PlainText-{normalizedEncodingName}"
3746 };
3747 }
3748
3772 private static string NormalizeTextEncodingName(string encodingName)
3773 {
3774 if (string.Equals(encodingName, PlainTextProtocolOptions.KoreanCodePage949EncodingName, StringComparison.OrdinalIgnoreCase) ||
3775 string.Equals(encodingName, "949", StringComparison.OrdinalIgnoreCase))
3776 {
3777 return PlainTextProtocolOptions.KoreanCodePage949EncodingName;
3778 }
3779
3780 return PlainTextProtocolOptions.Utf8EncodingName;
3781 }
3782
3783
3808 private static int GetUdpLocalPort(string peerName)
3809 {
3810 return NormalizeUdpPeerName(peerName) == "B"
3813 }
3814
3839 private static int GetUdpRemotePort(string peerName)
3840 {
3841 return NormalizeUdpPeerName(peerName) == "B"
3844 }
3845
3870 private static string NormalizeUdpPeerName(string peerName)
3871 {
3872 return string.Equals(peerName, "B", StringComparison.OrdinalIgnoreCase)
3873 ? "B"
3874 : "A";
3875 }
3876
3925 private static MessageEnvelope CreateTcpMessageByProtocol(
3926 string protocol,
3927 string direction,
3928 string text,
3929 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
3930 {
3931 var normalizedProtocol = NormalizeProtocol(protocol);
3932 var normalizedEncodingName = NormalizeTextEncodingName(encodingName);
3933 var payload = Encoding.UTF8.GetBytes(text);
3934
3935 return normalizedProtocol switch
3936 {
3937 DreamineEnvelopeProtocol => new MessageEnvelope
3938 {
3939 Name = $"Tcp.{direction}.DreamineEnvelope",
3940 Route = "sample.communication.tcp",
3941 Payload = payload,
3942 Headers = new Dictionary<string, string>
3943 {
3944 ["Protocol"] = DreamineEnvelopeProtocol
3945 }
3946 },
3947
3948 PlainTextProtocol => new MessageEnvelope
3949 {
3950 Name = $"Tcp.{direction}.PlainText",
3951 Route = "tcp.plaintext",
3952 Payload = payload,
3953 Headers = new Dictionary<string, string>
3954 {
3955 ["ContentType"] = "text/plain",
3956 ["Protocol"] = PlainTextProtocol,
3957 ["ExternalEncoding"] = normalizedEncodingName
3958 }
3959 },
3960
3961 RawAvailableProtocol => new MessageEnvelope
3962 {
3963 Name = $"Tcp.{direction}.RawAvailable",
3964 Route = "tcp.raw.available",
3965 Payload = payload,
3966 Headers = new Dictionary<string, string>
3967 {
3968 ["ContentType"] = "text/plain",
3969 ["Protocol"] = RawAvailableProtocol,
3970 ["ExternalEncoding"] = normalizedEncodingName
3971 }
3972 },
3973
3974 RawJsonProtocol => new MessageEnvelope
3975 {
3976 Name = $"Tcp.{direction}.RawJson",
3977 Route = "tcp.rawjson",
3978 Payload = EnsureJsonPayload(text),
3979 Headers = new Dictionary<string, string>
3980 {
3981 ["ContentType"] = "application/json",
3982 ["Protocol"] = RawJsonProtocol
3983 }
3984 },
3985
3986 _ => new MessageEnvelope
3987 {
3988 Name = $"Tcp.{direction}.PlainText",
3989 Route = "tcp.plaintext",
3990 Payload = payload,
3991 Headers = new Dictionary<string, string>
3992 {
3993 ["ContentType"] = "text/plain",
3994 ["Protocol"] = PlainTextProtocol,
3995 ["ExternalEncoding"] = normalizedEncodingName
3996 }
3997 }
3998 };
3999 }
4000
4049 private static MessageEnvelope CreateUdpMessageByProtocol(
4050 string protocol,
4051 string direction,
4052 string text,
4053 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
4054 {
4055 var normalizedProtocol = NormalizeProtocol(protocol);
4056 var normalizedEncodingName = NormalizeTextEncodingName(encodingName);
4057 var payload = Encoding.UTF8.GetBytes(text);
4058
4059 return normalizedProtocol switch
4060 {
4061 DreamineEnvelopeProtocol => new MessageEnvelope
4062 {
4063 Name = $"Udp.{direction}.DreamineEnvelope",
4064 Route = "sample.communication.udp",
4065 Payload = payload,
4066 Headers = new Dictionary<string, string>
4067 {
4068 ["Protocol"] = DreamineEnvelopeProtocol
4069 }
4070 },
4071
4072 PlainTextProtocol => new MessageEnvelope
4073 {
4074 Name = $"Udp.{direction}.PlainText",
4075 Route = "udp.plaintext",
4076 Payload = payload,
4077 Headers = new Dictionary<string, string>
4078 {
4079 ["ContentType"] = "text/plain",
4080 ["Protocol"] = PlainTextProtocol,
4081 ["ExternalEncoding"] = normalizedEncodingName
4082 }
4083 },
4084
4085 RawAvailableProtocol => new MessageEnvelope
4086 {
4087 Name = $"Udp.{direction}.RawAvailable",
4088 Route = "udp.raw.available",
4089 Payload = payload,
4090 Headers = new Dictionary<string, string>
4091 {
4092 ["ContentType"] = "text/plain",
4093 ["Protocol"] = RawAvailableProtocol,
4094 ["ExternalEncoding"] = normalizedEncodingName
4095 }
4096 },
4097
4098 RawJsonProtocol => new MessageEnvelope
4099 {
4100 Name = $"Udp.{direction}.RawJson",
4101 Route = "udp.rawjson",
4102 Payload = EnsureJsonPayload(text),
4103 Headers = new Dictionary<string, string>
4104 {
4105 ["ContentType"] = "application/json",
4106 ["Protocol"] = RawJsonProtocol
4107 }
4108 },
4109
4110 _ => new MessageEnvelope
4111 {
4112 Name = $"Udp.{direction}.PlainText",
4113 Route = "udp.plaintext",
4114 Payload = payload,
4115 Headers = new Dictionary<string, string>
4116 {
4117 ["ContentType"] = "text/plain",
4118 ["Protocol"] = PlainTextProtocol,
4119 ["ExternalEncoding"] = normalizedEncodingName
4120 }
4121 }
4122 };
4123 }
4124
4173 private static MessageEnvelope CreateSerialMessageByProtocol(
4174 string protocol,
4175 string direction,
4176 string text,
4177 string encodingName = PlainTextProtocolOptions.Utf8EncodingName)
4178 {
4179 var normalizedProtocol = NormalizeProtocol(protocol);
4180 var normalizedEncodingName = NormalizeTextEncodingName(encodingName);
4181 var payload = Encoding.UTF8.GetBytes(text);
4182
4183 return normalizedProtocol switch
4184 {
4185 DreamineEnvelopeProtocol => new MessageEnvelope
4186 {
4187 Name = $"Serial.{direction}.DreamineEnvelope",
4188 Route = "sample.communication.serial",
4189 Payload = payload,
4190 Headers = new Dictionary<string, string>
4191 {
4192 ["Protocol"] = DreamineEnvelopeProtocol
4193 }
4194 },
4195
4196 PlainTextProtocol => new MessageEnvelope
4197 {
4198 Name = $"Serial.{direction}.PlainText",
4199 Route = "serial.plaintext",
4200 Payload = payload,
4201 Headers = new Dictionary<string, string>
4202 {
4203 ["ContentType"] = "text/plain",
4204 ["Protocol"] = PlainTextProtocol,
4205 ["ExternalEncoding"] = normalizedEncodingName
4206 }
4207 },
4208
4209 RawAvailableProtocol => new MessageEnvelope
4210 {
4211 Name = $"Serial.{direction}.RawAvailable",
4212 Route = "serial.raw.available",
4213 Payload = payload,
4214 Headers = new Dictionary<string, string>
4215 {
4216 ["ContentType"] = "text/plain",
4217 ["Protocol"] = RawAvailableProtocol,
4218 ["ExternalEncoding"] = normalizedEncodingName
4219 }
4220 },
4221
4222 RawJsonProtocol => new MessageEnvelope
4223 {
4224 Name = $"Serial.{direction}.RawJson",
4225 Route = "serial.rawjson",
4226 Payload = EnsureJsonPayload(text),
4227 Headers = new Dictionary<string, string>
4228 {
4229 ["ContentType"] = "application/json",
4230 ["Protocol"] = RawJsonProtocol
4231 }
4232 },
4233
4234 _ => new MessageEnvelope
4235 {
4236 Name = $"Serial.{direction}.PlainText",
4237 Route = "serial.plaintext",
4238 Payload = payload,
4239 Headers = new Dictionary<string, string>
4240 {
4241 ["ContentType"] = "text/plain",
4242 ["Protocol"] = PlainTextProtocol,
4243 ["ExternalEncoding"] = normalizedEncodingName
4244 }
4245 }
4246 };
4247 }
4248
4289 private static MessageEnvelope CreateRabbitMqMessage(
4290 string direction,
4291 string route,
4292 string text)
4293 {
4294 return new MessageEnvelope
4295 {
4296 Name = $"RabbitMQ.{direction}",
4297 Route = route,
4298 Payload = Encoding.UTF8.GetBytes(text),
4299 Headers = new Dictionary<string, string>
4300 {
4301 ["ContentType"] = "text/plain",
4302 ["Protocol"] = RabbitMqProtocol
4303 }
4304 };
4305 }
4306
4355 private static MessageEnvelope CreateTextMessage(
4356 string name,
4357 string route,
4358 string text,
4359 string protocol)
4360 {
4361 return new MessageEnvelope
4362 {
4363 Name = name,
4364 Route = route,
4365 Payload = Encoding.UTF8.GetBytes(text),
4366 Headers = new Dictionary<string, string>
4367 {
4368 ["ContentType"] = "text/plain",
4369 ["Protocol"] = protocol
4370 }
4371 };
4372 }
4373
4399 string name,
4400 string text)
4401 {
4402 var message = CreateTextMessage(
4403 name,
4405 text,
4407
4408 Monitor.AddReceiveLog(
4410 TransportKind.RabbitMq,
4411 message);
4412 }
4413
4438 private static byte[] EnsureJsonPayload(string text)
4439 {
4440 if (string.IsNullOrWhiteSpace(text))
4441 {
4442 text = "{\"cmd\":\"PING\"}";
4443 }
4444
4445 var trimmed = text.Trim();
4446
4447 if (trimmed.StartsWith("{", StringComparison.Ordinal) ||
4448 trimmed.StartsWith("[", StringComparison.Ordinal))
4449 {
4450 return Encoding.UTF8.GetBytes(trimmed);
4451 }
4452
4453 var json = $$"""
4454 {"message":"{{EscapeJsonString(text)}}"}
4455 """;
4456
4457 return Encoding.UTF8.GetBytes(json);
4458 }
4459
4484 private static string EscapeJsonString(string value)
4485 {
4486 return value
4487 .Replace("\\", "\\\\", StringComparison.Ordinal)
4488 .Replace("\"", "\\\"", StringComparison.Ordinal)
4489 .Replace("\r", "\\r", StringComparison.Ordinal)
4490 .Replace("\n", "\\n", StringComparison.Ordinal);
4491 }
4492
4517 private static TcpServerSendTargetMode NormalizeTcpServerSendTargetMode(string? sendTargetMode)
4518 {
4519 if (Enum.TryParse<TcpServerSendTargetMode>(
4520 sendTargetMode,
4521 ignoreCase: true,
4522 out var parsed))
4523 {
4524 return parsed;
4525 }
4526
4527 return TcpServerSendTargetMode.Broadcast;
4528 }
4529
4554 private static string NormalizeProtocol(string? protocol)
4555 {
4556 if (string.IsNullOrWhiteSpace(protocol))
4557 {
4558 return PlainTextProtocol;
4559 }
4560
4561 return protocol.Trim() switch
4562 {
4568 };
4569 }
4570
4603 private static string NormalizeText(
4604 string? value,
4605 string defaultValue)
4606 {
4607 return string.IsNullOrWhiteSpace(value)
4608 ? defaultValue
4609 : value.Trim();
4610 }
4611
4628 private static void RunOnUiThread(Action action)
4629 {
4630 ArgumentNullException.ThrowIfNull(action);
4631
4632 var dispatcher = Application.Current?.Dispatcher;
4633
4634 if (dispatcher is null || dispatcher.CheckAccess())
4635 {
4636 action();
4637 return;
4638 }
4639
4640 dispatcher.Invoke(action);
4641 }
4642}
void AttachTcpResilientStateMonitor(IMessageTransport transport, string channelName)
async Task ConnectUdpPeerAAsync(string protocol, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
async void OnTcpServerMessageReceived(object? sender, MessageEnvelope message)
static IMessageFrameCodec CreateFrameCodec(string protocol, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
async Task SubscribeRabbitMqAsync(string exchangeName, string queueName, string routingKey)
async Task SendUdpPeerBAsync(string protocol, string text, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
async Task PublishRabbitMqAsync(string exchangeName, string routingKey, string text)
async Task PrepareTcpClientTransportAsync(string protocol, string encodingName)
async Task ConnectTcpClientAsync(string protocol, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
void AttachTcpClientQueueMonitor(IMessageTransport transport, string protocol, string encodingName, string channelName)
void AttachTcpServerClientCountMonitor(TcpServerTransport tcpServerTransport, string protocol, string encodingName)
void EnsureUdpPeerChannel(string peerName, string protocol, string encodingName)
static TcpServerSendTargetMode NormalizeTcpServerSendTargetMode(string? sendTargetMode)
async Task StartTcpServerAsync(string protocol, string encodingName=PlainTextProtocolOptions.Utf8EncodingName, string sendTargetMode=nameof(TcpServerSendTargetMode.Broadcast), bool echoEnabled=false)
static string GetTcpServerChannelName(string protocol, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
static string GetTcpClientChannelName(string protocol, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
static string GetUdpPeerChannelName(string peerName, string protocol, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
static IMessageProtocolAdapter CreateProtocolAdapter(string protocol, string routePrefix="tcp", string namePrefix="Tcp", string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
static MessageEnvelope CreateRabbitMqMessage(string direction, string route, string text)
void UpdateTcpServerDescription(string protocol, string encodingName, int clientCount, TcpServerSendTargetMode targetMode, bool echoEnabled)
async Task SendSerialAsync(string protocol, string text, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
static MessageEnvelope CreateTextMessage(string name, string route, string text, string protocol)
async Task SendTcpServerAsync(string protocol, string text, string encodingName=PlainTextProtocolOptions.Utf8EncodingName, string sendTargetMode=nameof(TcpServerSendTargetMode.Broadcast))
async Task SendTcpClientAsync(string protocol, string text, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
async Task ConnectRabbitMqAsync(string host, int port, string virtualHost, string userName, string password, string exchangeName, string queueName, string routingKey)
static string CreateTcpServerDescription(string protocol, string encodingName, int port, int clientCount, TcpServerSendTargetMode targetMode, bool echoEnabled)
void UpdateTcpServerOptions(string protocol, string encodingName=PlainTextProtocolOptions.Utf8EncodingName, string sendTargetMode=nameof(TcpServerSendTargetMode.Broadcast), bool echoEnabled=false)
void EnsureTcpServerChannel(string protocol, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
static MessageEnvelope CreateTcpMessageByProtocol(string protocol, string direction, string text, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
static MessageEnvelope CreateUdpMessageByProtocol(string protocol, string direction, string text, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
static MessageEnvelope CreateSerialMessageByProtocol(string protocol, string direction, string text, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
async Task StartUdpLoopbackAsync(string protocol, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
async Task ConnectUdpPeerBAsync(string protocol, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
async Task ConnectSerialAsync(string portName, int baudRate, string protocol, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
void EnsureTcpClientChannel(string protocol, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)
async Task SendUdpPeerAAsync(string protocol, string text, string encodingName=PlainTextProtocolOptions.Utf8EncodingName)