MainViewModel.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. using Newtonsoft.Json;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Collections.ObjectModel;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Net;
  8. using System.Net.Http;
  9. using System.Net.NetworkInformation;
  10. using System.Net.Sockets;
  11. using System.Text;
  12. using System.Text.RegularExpressions;
  13. using System.Threading;
  14. using System.Threading.Tasks;
  15. using System.Windows.Input;
  16. using Vinno.IUS.Common.Client.ViewModels;
  17. namespace SonopostSearchTool
  18. {
  19. public class MainViewModel : ViewModel
  20. {
  21. private CancellationTokenSource _tokenSource;
  22. private Socket _socket;
  23. private int _listenerPort = 9099;
  24. private bool _isBusy;
  25. private string _fixedIp;
  26. private string _url;
  27. private VBoxItem _selectedItem;
  28. private string _status;
  29. public bool IsBusy
  30. {
  31. get => _isBusy;
  32. set
  33. {
  34. if (_isBusy != value)
  35. {
  36. _isBusy = value;
  37. OnPropertyChanged(() => IsBusy);
  38. }
  39. }
  40. }
  41. public string FixedIP
  42. {
  43. get => _fixedIp;
  44. set
  45. {
  46. if(_fixedIp != value)
  47. {
  48. _fixedIp = value;
  49. OnPropertyChanged(()=> FixedIP);
  50. }
  51. }
  52. }
  53. public string Url
  54. {
  55. get => _url;
  56. set
  57. {
  58. if(_url != value)
  59. {
  60. _url = value;
  61. OnPropertyChanged(()=>Url);
  62. }
  63. }
  64. }
  65. public VBoxItem SelectedItem
  66. {
  67. get => _selectedItem;
  68. set
  69. {
  70. if(_selectedItem != value)
  71. {
  72. _selectedItem = value;
  73. Url = _selectedItem?.Url ?? "about:blank";
  74. if(_selectedItem != null && !string.IsNullOrEmpty(_selectedItem.IP))
  75. {
  76. Status = string.Format(TranslateHelper.Translate("Connected"), _selectedItem.DisplayName);
  77. }
  78. OnPropertyChanged(()=>SelectedItem);
  79. }
  80. }
  81. }
  82. public string Status
  83. {
  84. get => _status;
  85. set
  86. {
  87. if(_status != value)
  88. {
  89. _status = value;
  90. OnPropertyChanged(()=>Status);
  91. }
  92. }
  93. }
  94. public ICommand OpenCommand { get; set; }
  95. public ICommand RefreshCommand { get; set; }
  96. public ObservableCollection<VBoxItem> VBoxItems { get; set; }
  97. public MainViewModel()
  98. {
  99. VBoxItems = new ObservableCollection<VBoxItem>();
  100. OpenCommand = new ButtonCommand(OnOpenAsync);
  101. RefreshCommand = new ButtonCommand(OnRefresh);
  102. }
  103. private async void OnOpenAsync(object obj)
  104. {
  105. try
  106. {
  107. IsBusy = true;
  108. if (string.IsNullOrEmpty(FixedIP))
  109. {
  110. ShowMessage("AddressIsEmpty");
  111. return;
  112. }
  113. string reg = @"^((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})(\.((2(5[0-5]|[0-4]\d))|[0-1]?\d{1,2})){3}$";
  114. if (Regex.IsMatch(FixedIP, reg) == false)
  115. {
  116. ShowMessage("IPAddressIsWrong");
  117. return;
  118. }
  119. var result = await CheckIsExist(FixedIP);
  120. if (result == true)
  121. {
  122. Url = $"http://{FixedIP}:8080";
  123. }
  124. else
  125. {
  126. ShowMessage("DeviceIsWrong");
  127. }
  128. }
  129. catch (Exception e)
  130. {
  131. Logger.WriteLineError($"Open VBOX Error:{e}");
  132. }
  133. finally
  134. {
  135. IsBusy = false;
  136. }
  137. }
  138. private async Task<bool> CheckIsExist(string url)
  139. {
  140. try
  141. {
  142. var ip = url.Split(':')[0];
  143. var gateway = ip.Substring(0, ip.LastIndexOf('.')) + ".1";
  144. using (var httpClient = new HttpClient())
  145. {
  146. httpClient.Timeout = TimeSpan.FromSeconds(2);
  147. var result = await httpClient.PostAsync($"http://{url}/api/vbox?flag=ping&address={gateway}", null);
  148. if (result != null && result.StatusCode == HttpStatusCode.OK)
  149. {
  150. var jsonstr = await result.Content.ReadAsStringAsync();
  151. var msg = JsonConvert.DeserializeObject<PingMessage>(jsonstr);
  152. if (msg.Status == "200" && msg.Content.Contains("Success"))
  153. {
  154. return true;
  155. }
  156. }
  157. }
  158. }
  159. catch(TaskCanceledException)
  160. {
  161. //ignore
  162. }
  163. catch (Exception e)
  164. {
  165. Logger.WriteLineError($"Check VBox Exist Error:{e}");
  166. }
  167. return false;
  168. }
  169. private void OnRefresh(object obj)
  170. {
  171. try
  172. {
  173. Status = string.Empty;
  174. VBoxItems.Clear();
  175. Init();
  176. var localIps = GetAddressIP();
  177. StartSearch(localIps);
  178. }
  179. catch (Exception e)
  180. {
  181. Logger.WriteLineError($"Refresh Error:{e}");
  182. }
  183. }
  184. private IList<string> GetAddressIP()
  185. {
  186. IList<string> ips = new List<string>();
  187. foreach (IPAddress ipaddress in Dns.GetHostEntry(Dns.GetHostName()).AddressList)
  188. {
  189. if (ipaddress.AddressFamily == AddressFamily.InterNetwork)
  190. {
  191. if(!string.IsNullOrEmpty(ipaddress.ToString()))
  192. {
  193. ips.Add(ipaddress.ToString());
  194. }
  195. }
  196. }
  197. return ips;
  198. }
  199. private void Init()
  200. {
  201. try
  202. {
  203. if(_socket != null)
  204. {
  205. return;
  206. }
  207. var ipProperties = IPGlobalProperties.GetIPGlobalProperties();
  208. var ipEndPoints = ipProperties.GetActiveUdpListeners();
  209. // calculate port is in use or not
  210. while (ipEndPoints.Any(x => x.Port == _listenerPort))
  211. {
  212. _listenerPort++;
  213. }
  214. _socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
  215. uint IOC_IN = 0x80000000;
  216. uint IOC_VENDOR = 0x18000000;
  217. uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
  218. _socket.IOControl((int)SIO_UDP_CONNRESET, new byte[] { Convert.ToByte(false) }, null);
  219. //_socket.ReceiveTimeout = 3000;
  220. _socket.Bind(new IPEndPoint(IPAddress.Any, _listenerPort));
  221. StartReceiveThread();
  222. }
  223. catch (Exception e)
  224. {
  225. _listenerPort++;
  226. Logger.WriteLineError($"Start UDP Search Error:{e}");
  227. }
  228. }
  229. private void StartSearch(IList<string> localIps)
  230. {
  231. if (!localIps.Any())
  232. {
  233. return;
  234. }
  235. if (_tokenSource != null && !_tokenSource.IsCancellationRequested)
  236. {
  237. _tokenSource.Cancel();
  238. }
  239. _tokenSource = new CancellationTokenSource();
  240. Task.Run(async () => {
  241. try
  242. {
  243. MainDispatcher.Invoke(()=> IsBusy = true);
  244. foreach (var ip in localIps)
  245. {
  246. await SendMsgToServerAsync(ip);
  247. }
  248. }
  249. catch (TaskCanceledException)
  250. {
  251. //ignore
  252. }
  253. catch (Exception e)
  254. {
  255. Logger.WriteLineError($"StartSendPacages Error:{e}");
  256. }
  257. finally
  258. {
  259. MainDispatcher.Invoke(() =>
  260. {
  261. IsBusy = false;
  262. });
  263. }
  264. }, _tokenSource.Token);
  265. }
  266. private async Task SendMsgToServerAsync(string localIp)
  267. {
  268. var index = localIp.LastIndexOf('.');
  269. var tmp = localIp.Substring(0, index + 1);
  270. var localIndex = int.Parse(localIp.Substring(index + 1, localIp.Length - index - 1));
  271. for (int i = 0; i <= 255; i++)
  272. {
  273. if (_tokenSource.IsCancellationRequested)
  274. {
  275. return;
  276. }
  277. if (i == 1 || i == localIndex)
  278. {
  279. continue;
  280. }
  281. var ipaddress = IPAddress.Parse($"{tmp}{i}");
  282. var portData = BitConverter.GetBytes(_listenerPort);
  283. using (var ms = new MemoryStream())
  284. {
  285. ms.WriteByte(0x4C);
  286. ms.WriteByte(0x54);
  287. ms.Write(portData, 0, portData.Length);
  288. _socket.SendTo(ms.ToArray(), new IPEndPoint(ipaddress, 8888));
  289. }
  290. await Task.Delay(10, _tokenSource.Token);
  291. }
  292. }
  293. private void StopSearch()
  294. {
  295. _tokenSource?.Cancel();
  296. }
  297. private void StartReceiveThread()
  298. {
  299. Task.Run(() => {
  300. while (_socket != null)
  301. {
  302. try
  303. {
  304. var buffer = new byte[1024];
  305. EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); ;
  306. _socket.ReceiveFrom(buffer, ref remoteEndPoint);
  307. var bytesLen = new byte[4];
  308. Buffer.BlockCopy(buffer, 0, bytesLen, 0, 4);
  309. var bufferLen = BitConverter.ToInt32(bytesLen, 0);
  310. var contentBytes = new byte[bufferLen];
  311. Buffer.BlockCopy(buffer, 4, contentBytes, 0, bufferLen);
  312. var packageStr = Encoding.UTF8.GetString(contentBytes).TrimEnd();
  313. if (string.IsNullOrWhiteSpace(packageStr))
  314. continue;
  315. var package = JsonConvert.DeserializeObject<DevicePackage>(packageStr);
  316. if (package != null)
  317. {
  318. var vboxIp = package.NetworkInfo.FirstOrDefault()?.IP;
  319. var vboxItem = new VBoxItem(vboxIp,package.Port, package.Version);
  320. MainDispatcher.Invoke(new Action(()=> {
  321. if(VBoxItems.FirstOrDefault(c=>c.IP == vboxIp) == null)
  322. {
  323. VBoxItems.Add(vboxItem);
  324. }
  325. }));
  326. }
  327. }
  328. catch (TaskCanceledException)
  329. {
  330. //ignore
  331. }
  332. catch (Exception e)
  333. {
  334. Logger.WriteLineError($"Receive UDP Error:{e}");
  335. }
  336. }
  337. });
  338. }
  339. private void ShowMessage(string msg)
  340. {
  341. MainDispatcher.Invoke(() => {
  342. CustomMessageBox.Show(TranslateHelper.Translate(msg));
  343. });
  344. }
  345. protected override void DoDispose()
  346. {
  347. try
  348. {
  349. _tokenSource?.Cancel();
  350. if(_socket != null)
  351. {
  352. _socket.Close();
  353. _socket.Dispose();
  354. _socket = null;
  355. }
  356. base.DoDispose();
  357. }
  358. catch (Exception e)
  359. {
  360. Logger.WriteLineError($"DoDispose:{e}");
  361. }
  362. }
  363. private class PingMessage
  364. {
  365. public string Status { get; set; }
  366. public string Content { get; set; }
  367. }
  368. }
  369. }