You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

584 lines
19 KiB

  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Text;
  4. using System.Threading.Tasks;
  5. using Windows.Security.Cryptography.Certificates;
  6. using Windows.UI.Core;
  7. using Windows.UI.Xaml;
  8. using MQTTnet.Client;
  9. using MQTTnet.Diagnostics;
  10. using MQTTnet.Exceptions;
  11. using MQTTnet.Extensions.Rpc;
  12. using MQTTnet.Implementations;
  13. using MQTTnet.ManagedClient;
  14. using MQTTnet.Protocol;
  15. using MQTTnet.Server;
  16. namespace MQTTnet.TestApp.UniversalWindows
  17. {
  18. public sealed partial class MainPage
  19. {
  20. private readonly ConcurrentQueue<MqttNetLogMessage> _traceMessages = new ConcurrentQueue<MqttNetLogMessage>();
  21. private IMqttClient _mqttClient;
  22. private IMqttServer _mqttServer;
  23. public MainPage()
  24. {
  25. InitializeComponent();
  26. MqttNetGlobalLogger.LogMessagePublished += OnTraceMessagePublished;
  27. }
  28. private async void OnTraceMessagePublished(object sender, MqttNetLogMessagePublishedEventArgs e)
  29. {
  30. _traceMessages.Enqueue(e.TraceMessage);
  31. while (_traceMessages.Count > 100)
  32. {
  33. _traceMessages.TryDequeue(out _);
  34. }
  35. var logText = new StringBuilder();
  36. foreach (var traceMessage in _traceMessages)
  37. {
  38. logText.AppendFormat(
  39. "[{0:yyyy-MM-dd HH:mm:ss.fff}] [{1}] [{2}] [{3}] [{4}]{5}",
  40. traceMessage.Timestamp,
  41. traceMessage.Level,
  42. traceMessage.Source,
  43. traceMessage.ThreadId,
  44. traceMessage.Message,
  45. Environment.NewLine);
  46. if (traceMessage.Exception != null)
  47. {
  48. logText.AppendLine(traceMessage.Exception.ToString());
  49. }
  50. }
  51. await Trace.Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
  52. {
  53. Trace.Text = logText.ToString();
  54. });
  55. }
  56. private async void Connect(object sender, RoutedEventArgs e)
  57. {
  58. var tlsOptions = new MqttClientTlsOptions
  59. {
  60. UseTls = UseTls.IsChecked == true,
  61. IgnoreCertificateChainErrors = true,
  62. IgnoreCertificateRevocationErrors = true,
  63. AllowUntrustedCertificates = true
  64. };
  65. var options = new MqttClientOptions { ClientId = ClientId.Text };
  66. if (UseTcp.IsChecked == true)
  67. {
  68. options.ChannelOptions = new MqttClientTcpOptions
  69. {
  70. Server = Server.Text,
  71. Port = int.Parse(Port.Text),
  72. TlsOptions = tlsOptions
  73. };
  74. }
  75. if (UseWs.IsChecked == true)
  76. {
  77. options.ChannelOptions = new MqttClientWebSocketOptions
  78. {
  79. Uri = Server.Text,
  80. TlsOptions = tlsOptions
  81. };
  82. }
  83. if (options.ChannelOptions == null)
  84. {
  85. throw new InvalidOperationException();
  86. }
  87. options.Credentials = new MqttClientCredentials
  88. {
  89. Username = User.Text,
  90. Password = Password.Text
  91. };
  92. options.CleanSession = CleanSession.IsChecked == true;
  93. options.KeepAlivePeriod = TimeSpan.FromSeconds(double.Parse(KeepAliveInterval.Text));
  94. try
  95. {
  96. if (_mqttClient != null)
  97. {
  98. await _mqttClient.DisconnectAsync();
  99. _mqttClient.ApplicationMessageReceived -= OnApplicationMessageReceived;
  100. }
  101. var factory = new MqttFactory();
  102. _mqttClient = factory.CreateMqttClient();
  103. _mqttClient.ApplicationMessageReceived += OnApplicationMessageReceived;
  104. await _mqttClient.ConnectAsync(options);
  105. }
  106. catch (Exception exception)
  107. {
  108. Trace.Text += exception + Environment.NewLine;
  109. }
  110. }
  111. private async void OnApplicationMessageReceived(object sender, MqttApplicationMessageReceivedEventArgs eventArgs)
  112. {
  113. var item = $"Timestamp: {DateTime.Now:O} | Topic: {eventArgs.ApplicationMessage.Topic} | Payload: {Encoding.UTF8.GetString(eventArgs.ApplicationMessage.Payload)} | QoS: {eventArgs.ApplicationMessage.QualityOfServiceLevel}";
  114. await Dispatcher.RunAsync(CoreDispatcherPriority.Low, () =>
  115. {
  116. if (AddReceivedMessagesToList.IsChecked == true)
  117. {
  118. ReceivedMessages.Items.Add(item);
  119. }
  120. });
  121. }
  122. private async void Publish(object sender, RoutedEventArgs e)
  123. {
  124. if (_mqttClient == null)
  125. {
  126. return;
  127. }
  128. try
  129. {
  130. var qos = MqttQualityOfServiceLevel.AtMostOnce;
  131. if (QoS1.IsChecked == true)
  132. {
  133. qos = MqttQualityOfServiceLevel.AtLeastOnce;
  134. }
  135. if (QoS2.IsChecked == true)
  136. {
  137. qos = MqttQualityOfServiceLevel.ExactlyOnce;
  138. }
  139. var payload = new byte[0];
  140. if (Text.IsChecked == true)
  141. {
  142. payload = Encoding.UTF8.GetBytes(Payload.Text);
  143. }
  144. if (Base64.IsChecked == true)
  145. {
  146. payload = Convert.FromBase64String(Payload.Text);
  147. }
  148. var message = new MqttApplicationMessageBuilder()
  149. .WithTopic(Topic.Text)
  150. .WithPayload(payload)
  151. .WithQualityOfServiceLevel(qos)
  152. .WithRetainFlag(Retain.IsChecked == true)
  153. .Build();
  154. await _mqttClient.PublishAsync(message);
  155. }
  156. catch (Exception exception)
  157. {
  158. Trace.Text += exception + Environment.NewLine;
  159. }
  160. }
  161. private async void Disconnect(object sender, RoutedEventArgs e)
  162. {
  163. try
  164. {
  165. await _mqttClient.DisconnectAsync();
  166. }
  167. catch (Exception exception)
  168. {
  169. Trace.Text += exception + Environment.NewLine;
  170. }
  171. }
  172. private void ClearLog(object sender, RoutedEventArgs e)
  173. {
  174. while (_traceMessages.Count > 0)
  175. {
  176. _traceMessages.TryDequeue(out _);
  177. }
  178. Trace.Text = string.Empty;
  179. }
  180. private async void Subscribe(object sender, RoutedEventArgs e)
  181. {
  182. if (_mqttClient == null)
  183. {
  184. return;
  185. }
  186. try
  187. {
  188. var qos = MqttQualityOfServiceLevel.AtMostOnce;
  189. if (SubscribeQoS1.IsChecked == true)
  190. {
  191. qos = MqttQualityOfServiceLevel.AtLeastOnce;
  192. }
  193. if (SubscribeQoS2.IsChecked == true)
  194. {
  195. qos = MqttQualityOfServiceLevel.ExactlyOnce;
  196. }
  197. await _mqttClient.SubscribeAsync(new TopicFilter(SubscribeTopic.Text, qos));
  198. }
  199. catch (Exception exception)
  200. {
  201. Trace.Text += exception + Environment.NewLine;
  202. }
  203. }
  204. private async void Unsubscribe(object sender, RoutedEventArgs e)
  205. {
  206. if (_mqttClient == null)
  207. {
  208. return;
  209. }
  210. try
  211. {
  212. await _mqttClient.UnsubscribeAsync(SubscribeTopic.Text);
  213. }
  214. catch (Exception exception)
  215. {
  216. Trace.Text += exception + Environment.NewLine;
  217. }
  218. }
  219. // This code is for the Wiki at GitHub!
  220. // ReSharper disable once UnusedMember.Local
  221. private async void StartServer(object sender, RoutedEventArgs e)
  222. {
  223. if (_mqttServer != null)
  224. {
  225. return;
  226. }
  227. JsonServerStorage storage = null;
  228. if (ServerPersistRetainedMessages.IsChecked == true)
  229. {
  230. storage = new JsonServerStorage();
  231. if (ServerClearRetainedMessages.IsChecked == true)
  232. {
  233. storage.Clear();
  234. }
  235. }
  236. _mqttServer = new MqttFactory().CreateMqttServer();
  237. var options = new MqttServerOptions();
  238. options.DefaultEndpointOptions.Port = int.Parse(ServerPort.Text);
  239. options.Storage = storage;
  240. await _mqttServer.StartAsync(options);
  241. }
  242. private async void StopServer(object sender, RoutedEventArgs e)
  243. {
  244. if (_mqttServer == null)
  245. {
  246. return;
  247. }
  248. await _mqttServer.StopAsync();
  249. _mqttServer = null;
  250. }
  251. private void ClearReceivedMessages(object sender, RoutedEventArgs e)
  252. {
  253. ReceivedMessages.Items.Clear();
  254. }
  255. private async void ExecuteRpc(object sender, RoutedEventArgs e)
  256. {
  257. var qos = MqttQualityOfServiceLevel.AtMostOnce;
  258. if (RpcQoS1.IsChecked == true)
  259. {
  260. qos = MqttQualityOfServiceLevel.AtLeastOnce;
  261. }
  262. if (RpcQoS2.IsChecked == true)
  263. {
  264. qos = MqttQualityOfServiceLevel.ExactlyOnce;
  265. }
  266. var payload = new byte[0];
  267. if (RpcText.IsChecked == true)
  268. {
  269. payload = Encoding.UTF8.GetBytes(RpcPayload.Text);
  270. }
  271. if (RpcBase64.IsChecked == true)
  272. {
  273. payload = Convert.FromBase64String(RpcPayload.Text);
  274. }
  275. try
  276. {
  277. var rpcClient = new MqttRpcClient(_mqttClient);
  278. await rpcClient.EnableAsync();
  279. var response = await rpcClient.ExecuteAsync(TimeSpan.FromSeconds(5), RpcMethod.Text, payload, qos);
  280. await rpcClient.DisableAsync();
  281. RpcResponses.Items.Add(RpcMethod.Text + " >>> " + Encoding.UTF8.GetString(response));
  282. }
  283. catch (MqttCommunicationTimedOutException)
  284. {
  285. RpcResponses.Items.Add(RpcMethod.Text + " >>> [TIMEOUT]");
  286. }
  287. }
  288. private void ClearRpcResponses(object sender, RoutedEventArgs e)
  289. {
  290. RpcResponses.Items.Clear();
  291. }
  292. private async Task WikiCode()
  293. {
  294. {
  295. // Write all trace messages to the console window.
  296. MqttNetGlobalLogger.LogMessagePublished += (s, e) =>
  297. {
  298. Console.WriteLine($">> [{e.TraceMessage.Timestamp:O}] [{e.TraceMessage.ThreadId}] [{e.TraceMessage.Source}] [{e.TraceMessage.Level}]: {e.TraceMessage.Message}");
  299. if (e.TraceMessage.Exception != null)
  300. {
  301. Console.WriteLine(e.TraceMessage.Exception);
  302. }
  303. };
  304. }
  305. {
  306. // Use a custom identifier for the trace messages.
  307. var clientOptions = new MqttClientOptionsBuilder()
  308. .Build();
  309. }
  310. {
  311. // Create a new MQTT client.
  312. var factory = new MqttFactory();
  313. var mqttClient = factory.CreateMqttClient();
  314. {
  315. // Create TCP based options using the builder.
  316. var options = new MqttClientOptionsBuilder()
  317. .WithClientId("Client1")
  318. .WithTcpServer("broker.hivemq.com")
  319. .WithCredentials("bud", "%spencer%")
  320. .WithTls()
  321. .WithCleanSession()
  322. .Build();
  323. await mqttClient.ConnectAsync(options);
  324. }
  325. {
  326. // Use TCP connection.
  327. var options = new MqttClientOptionsBuilder()
  328. .WithTcpServer("broker.hivemq.com", 1883) // Port is optional
  329. .Build();
  330. }
  331. {
  332. // Use secure TCP connection.
  333. var options = new MqttClientOptionsBuilder()
  334. .WithTcpServer("broker.hivemq.com")
  335. .WithTls()
  336. .Build();
  337. }
  338. {
  339. // Use WebSocket connection.
  340. var options = new MqttClientOptionsBuilder()
  341. .WithWebSocketServer("broker.hivemq.com:8000/mqtt")
  342. .Build();
  343. await mqttClient.ConnectAsync(options);
  344. }
  345. {
  346. // Create TCP based options manually
  347. var options = new MqttClientOptions
  348. {
  349. ClientId = "Client1",
  350. Credentials = new MqttClientCredentials
  351. {
  352. Username = "bud",
  353. Password = "%spencer%"
  354. },
  355. ChannelOptions = new MqttClientTcpOptions
  356. {
  357. Server = "broker.hivemq.org",
  358. TlsOptions = new MqttClientTlsOptions
  359. {
  360. UseTls = true
  361. }
  362. },
  363. };
  364. }
  365. {
  366. // Subscribe to a topic
  367. await mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic("my/topic").Build());
  368. // Unsubscribe from a topic
  369. await mqttClient.UnsubscribeAsync("my/topic");
  370. // Publish an application message
  371. var applicationMessage = new MqttApplicationMessageBuilder()
  372. .WithTopic("A/B/C")
  373. .WithPayload("Hello World")
  374. .WithAtLeastOnceQoS()
  375. .Build();
  376. await mqttClient.PublishAsync(applicationMessage);
  377. }
  378. }
  379. // ----------------------------------
  380. {
  381. var options = new MqttServerOptions();
  382. options.ConnectionValidator = c =>
  383. {
  384. if (c.ClientId.Length < 10)
  385. {
  386. c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedIdentifierRejected;
  387. return;
  388. }
  389. if (c.Username != "mySecretUser")
  390. {
  391. c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;
  392. return;
  393. }
  394. if (c.Password != "mySecretPassword")
  395. {
  396. c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;
  397. return;
  398. }
  399. c.ReturnCode = MqttConnectReturnCode.ConnectionAccepted;
  400. };
  401. var factory = new MqttFactory();
  402. var mqttServer = factory.CreateMqttServer();
  403. await mqttServer.StartAsync(options);
  404. Console.WriteLine("Press any key to exit.");
  405. Console.ReadLine();
  406. await mqttServer.StopAsync();
  407. }
  408. // ----------------------------------
  409. // For UWP apps:
  410. MqttTcpChannel.CustomIgnorableServerCertificateErrorsResolver = o =>
  411. {
  412. if (o.Server == "server_with_revoked_cert")
  413. {
  414. return new[] { ChainValidationResult.Revoked };
  415. }
  416. return new ChainValidationResult[0];
  417. };
  418. {
  419. // Start a MQTT server.
  420. var mqttServer = new MqttFactory().CreateMqttServer();
  421. await mqttServer.StartAsync(new MqttServerOptions());
  422. Console.WriteLine("Press any key to exit.");
  423. Console.ReadLine();
  424. await mqttServer.StopAsync();
  425. }
  426. {
  427. // Configure MQTT server.
  428. var optionsBuilder = new MqttServerOptionsBuilder()
  429. .WithConnectionBacklog(100)
  430. .WithDefaultEndpointPort(1884);
  431. var options = new MqttServerOptions
  432. {
  433. };
  434. options.ConnectionValidator = c =>
  435. {
  436. if (c.ClientId != "Highlander")
  437. {
  438. c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedIdentifierRejected;
  439. return;
  440. }
  441. c.ReturnCode = MqttConnectReturnCode.ConnectionAccepted;
  442. };
  443. var mqttServer = new MqttFactory().CreateMqttServer();
  444. await mqttServer.StartAsync(optionsBuilder.Build());
  445. }
  446. {
  447. // Setup client validator.
  448. var options = new MqttServerOptions
  449. {
  450. ConnectionValidator = c =>
  451. {
  452. if (c.ClientId.Length < 10)
  453. {
  454. c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedIdentifierRejected;
  455. return;
  456. }
  457. if (c.Username != "mySecretUser")
  458. {
  459. c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;
  460. return;
  461. }
  462. if (c.Password != "mySecretPassword")
  463. {
  464. c.ReturnCode = MqttConnectReturnCode.ConnectionRefusedBadUsernameOrPassword;
  465. return;
  466. }
  467. c.ReturnCode = MqttConnectReturnCode.ConnectionAccepted;
  468. }
  469. };
  470. }
  471. {
  472. // Create a new MQTT server.
  473. var mqttServer = new MqttFactory().CreateMqttServer();
  474. }
  475. {
  476. // Setup and start a managed MQTT client.
  477. var options = new ManagedMqttClientOptionsBuilder()
  478. .WithAutoReconnectDelay(TimeSpan.FromSeconds(5))
  479. .WithClientOptions(new MqttClientOptionsBuilder()
  480. .WithClientId("Client1")
  481. .WithTcpServer("broker.hivemq.com")
  482. .WithTls().Build())
  483. .Build();
  484. var mqttClient = new MqttFactory().CreateManagedMqttClient();
  485. await mqttClient.SubscribeAsync(new TopicFilterBuilder().WithTopic("my/topic").Build());
  486. await mqttClient.StartAsync(options);
  487. }
  488. }
  489. }
  490. }