{"id":336771,"date":"2022-08-09T09:00:16","date_gmt":"2022-08-09T09:00:16","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=336771"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=336771","title":{"rendered":"<span>\u041a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u044b\u0439 UI \u0438 \u043e\u0442\u043a\u0430\u0437 \u043e\u0442 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430 \u0432 idewave-cli<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/5d1\/b6e\/e42\/5d1b6ee4292303df78c3a75497492d37.png\" width=\"1680\" height=\"1050\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/5d1\/b6e\/e42\/5d1b6ee4292303df78c3a75497492d37.png\"\/><figcaption><\/figcaption><\/figure>\n<p>\u0421 \u0432\u044b\u0445\u043e\u0434\u043e\u043c \u0432\u0435\u0440\u0441\u0438\u0438 1.0.1 \u044f \u0440\u0435\u0448\u0438\u043b \u043e\u0441\u0432\u0435\u0442\u0438\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0430\u0441\u043f\u0435\u043a\u0442\u044b \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b <a href=\"https:\/\/github.com\/idewave\/idewave-cli\" rel=\"noopener noreferrer nofollow\">\u043c\u043e\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a>. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <em>tui-rs<\/em> \u0438 \u043f\u0440\u043e \u043d\u044e\u0430\u043d\u0441\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <em>tokio-rs<\/em>, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0436\u0435 \u0431\u044b\u043b\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e \u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0442\u0430\u043a, \u043a\u0430\u043a \u0431\u044b\u043b\u043e \u0440\u0430\u043d\u044c\u0448\u0435 \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u043d\u0430\u0434\u043e. \u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0432 \u0441\u0442\u0430\u0442\u044c\u044e &#8212; \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043a\u043e\u043c\u0443-\u0442\u043e \u043e\u043d\u0430 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430 \u0442\u0435\u0440\u043d\u0438\u0441\u0442\u043e\u043c \u043f\u0443\u0442\u0438 \u043f\u043e\u0433\u0440\u0443\u0436\u0435\u043d\u0438\u044f (\u0438\u043b\u0438 \u0432\u043e\u0441\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f) \u0432 Rust.<\/p>\n<hr\/>\n<p>\u041c\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f \u0438\u0433\u0440\u044b World of Warcraft (\u043d\u043e \u0441\u043b\u0443\u0436\u0438\u0442 \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u044d\u0442\u043e &#8212; \u043d\u0435 \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435). \u041f\u043e\u0441\u043b\u0435 \u043d\u0435\u0434\u0430\u0432\u043d\u0435\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u043d \u043e\u0431\u0437\u0430\u0432\u0435\u043b\u0441\u044f \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u0441\u0442\u0430\u043b \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u044e\u0437\u0430\u0431\u0435\u043b\u044c\u043d\u0435\u0435.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/708\/1c4\/0b9\/7081c40b98df4e6ae8d7bfe22d4a5d61.png\" alt=\"\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u043f\u043a\u043e\u0434\u043e\u0432 \u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\" title=\"\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u043f\u043a\u043e\u0434\u043e\u0432 \u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\" width=\"945\" height=\"443\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/708\/1c4\/0b9\/7081c40b98df4e6ae8d7bfe22d4a5d61.png\"\/><figcaption>\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u043f\u043a\u043e\u0434\u043e\u0432 \u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/figcaption><\/figure>\n<p>\u041d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043e\u0431\u044a\u0435\u043c\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u0439. \u041d\u0430\u0447\u043d\u0443 \u0441 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u044f \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0440\u0435\u0448\u0438\u043b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0432 \u0432\u0438\u0434\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0430\u0441\u043a\u0430 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434, \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0438\u0439\u0441\u044f \u043a UI. \u041d\u0430 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043c\u043e\u0438 \u0442\u0430\u0441\u043a\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432\u043e\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"rust\">join_all(vec![ self.handle_ui_render(), self.handle_ui_input(), self.handle_ui_output(),    self.handle_ai(), self.handle_queue(), self.handle_read(), self.handle_write(), ]).await;<\/code><\/pre>\n<p>\u0442\u0430\u0441\u043a\u0438, \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0438\u0435\u0441\u044f \u043a UI &#8212; \u0438\u0445 \u043f\u043e\u043a\u0430 \u0432\u0441\u0435\u0433\u043e \u0442\u0440\u0438. \u041f\u043e\u043c\u0438\u043c\u043e, \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0442\u0430\u0441\u043a\u0430 \u0434\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u044e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0442\u0430\u0441\u043a \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b \u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0442\u0430\u0441\u043a \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0442\u043a\u043b\u0438\u043a\u0430 \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430.<\/p>\n<p>\u0422\u0438\u043f\u0438\u0447\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442: \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u044b\u0431\u043e\u0440. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u044b\u0431\u043e\u0440 \u0440\u0438\u043b\u043c\u0430 (<em>realm<\/em>) \u0438\u043b\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0434\u043b\u044f \u0432\u0445\u043e\u0434\u0430 \u0432 \u043c\u0438\u0440. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0435-\u043d\u0438\u0431\u0443\u0434\u044c \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u043d\u043e. <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/9a6\/1d3\/81c\/9a61d381c20171a533d2f5d4e7d7f35d.png\" alt=\"\u0412\u044b\u0431\u043e\u0440 \u0440\u0438\u043b\u043c\u0430 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432 \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u043c \u043e\u043a\u043d\u0435\" title=\"\u0412\u044b\u0431\u043e\u0440 \u0440\u0438\u043b\u043c\u0430 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432 \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u043c \u043e\u043a\u043d\u0435\" width=\"944\" height=\"441\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9a6\/1d3\/81c\/9a61d381c20171a533d2f5d4e7d7f35d.png\"\/><figcaption>\u0412\u044b\u0431\u043e\u0440 \u0440\u0438\u043b\u043c\u0430 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432 \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u043c \u043e\u043a\u043d\u0435<\/figcaption><\/figure>\n<p>\u0417\u0434\u0435\u0441\u044c \u0432\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u0432 \u0441\u0438\u043b\u0443 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439:<\/p>\n<ol>\n<li>\n<p>\u044f \u0437\u0430\u043c\u043e\u0440\u0430\u0436\u0438\u0432\u0430\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 (\u0445\u043e\u0442\u044f, \u043f\u043e \u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u0438\u0445 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c)<\/p>\n<\/li>\n<li>\n<p>\u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u044e \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u043d\u043e \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439 \u0438\u043b\u0438 \u0440\u0438\u043b\u043c\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u043e\u0436\u0438\u0434\u0430\u044e, \u043f\u043e\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 &#8212; \u043d\u0430\u0436\u0430\u0442\u0438\u0435 \u0441\u0442\u0440\u0435\u043b\u043a\u0438 \u0432\u043d\u0438\u0437\/\u0432\u0432\u0435\u0440\u0445)<\/p>\n<\/li>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u044e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043d\u043e \u0443\u0436\u0435 \u0441 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c \u0432 \u0441\u043f\u0438\u0441\u043a\u0435<\/p>\n<\/li>\n<li>\n<p>\u0432 \u043a\u043e\u043d\u0446\u0435-\u043a\u043e\u043d\u0446\u043e\u0432, \u0432\u044b\u0431\u043e\u0440 \u0441\u0434\u0435\u043b\u0430\u043d, \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0430\u0436\u0430\u0442\u0438\u0435 Enter, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043d\u043e\u043c \u0432\u044b\u0431\u043e\u0440\u0435<\/p>\n<\/li>\n<li>\n<p>\u0438, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u044f \u0440\u0430\u0437\u043c\u043e\u0440\u0430\u0436\u0438\u0432\u0430\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u043a\u043e\u0434\u0435 \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"rust\">\/\/ \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0437\u0434\u0435\u0441\u044c (\u0441\u043c \u043f\u0443\u043d\u043a\u0442 3 \u0438 5) fn handle_ui_input(&amp;mut self) -> JoinHandle&lt;()> { let income_pipe = self._income_message_pipe.lock().unwrap();     \/\/ \u0441\u044e\u0434\u0430 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0432\u0441\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b let event_income = income_pipe.event_income.clone();  tokio::task::spawn_blocking(move || { let mut ui_input = UIInput::new(event_income);  loop { ui_input.handle(); } }) }  \/\/ \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0437\u0434\u0435\u0441\u044c (\u0441\u043c \u043f\u0443\u043d\u043a\u0442 2 \u0438 4) fn handle_ui_render(&amp;mut self) -> JoinHandle&lt;()> { \/\/ ... let outcome_message_pipe = self._outcome_message_pipe.lock().unwrap();     \/\/ \u043e\u0442\u043a\u043b\u0438\u043a \u043e\u0442 UI \u043e\u0442 \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u044b\u0445 \u043e\u043a\u043e\u043d let dialog_outcome = pipe.dialog_outcome.clone();     \/\/ ...  tokio::task::spawn_blocking(move || {         \/\/ UI renderer, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0443 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 let mut ui = UI::new( CrosstermBackend::new(std::io::stdout()), UIOutputOptions { dialog_outcome, \/\/ ... }, );  loop { \/\/ ...  ui.render(UIRenderOptions {                 \/\/ \u0432\u0441\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0437\u0434\u0435\u0441\u044c message: income_message_pipe.lock().unwrap().recv(), client_flags, }); } }) }  fn handle_ui_output(&amp;mut self) -> JoinHandle&lt;()> { let outcome_message_pipe = Arc::clone(&amp;self._outcome_message_pipe); \/\/ ...  tokio::task::spawn_blocking(move || { loop {             \/\/ \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u043e\u0442\u043a\u043b\u0438\u043a \u043e\u0442 UI \u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c, \u0435\u0441\u043b\u0438 \u043e\u043d \u0438\u043c\u0435\u0435\u0442\u0441\u044f if let Ok(message) = outcome_message_pipe.lock().unwrap().recv() { \/\/ ...  let mut ui_output = UIOutput::new(Arc::clone(&amp;session), client_flags);                 \/\/ \u044d\u0442\u0443 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0447\u0443\u0442\u044c \u043d\u0438\u0436\u0435 ui_output.handle(message); } } }) }<\/code><\/pre>\n<p>\u0412 <code>ui_output.handle(message)<\/code> \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0435 57 \u0432\u044b\u0448\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043c\u0435\u0436\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f (IPC) &#8212; \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u044d\u0442\u043e <code>session<\/code> , \u0430 \u0442\u0430\u043a \u0436\u0435 \u0447\u0435\u0440\u0435\u0437 \u0444\u043b\u0430\u0433\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0430\u043a\u0440\u043e\u0441\u0430 <code>bitflags!<\/code> \u0438\u0437 \u043e\u0434\u043d\u043e\u0438\u043c\u0435\u043d\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438):<\/p>\n<pre><code class=\"rust\">pub fn handle(&amp;mut self, message: OutcomeMessageType) { match message {         \/\/ \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043e\u0442\u043a\u043b\u0438\u043a, \u0447\u0442\u043e \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u0432\u044b\u0431\u0440\u0430\u043d \u043f\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044e Enter OutcomeMessageType::CharacterSelected(character) => {             \/\/ \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u0435\u0441\u0441\u0438\u0438 self.session.lock().unwrap().me = Some(Player::from(character));             \/\/ \u043c\u0435\u043d\u044f\u0435\u043c \u0444\u043b\u0430\u0433 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0440\u0430\u0437\u043c\u043e\u0440\u043e\u0437\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 (\u0441\u043c \u043f\u0443\u043d\u043a\u0442 6) self.client_flags.set(ClientFlags::IN_FROZEN_MODE, false); },         \/\/ \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043e\u0442\u043a\u043b\u0438\u043a, \u0447\u0442\u043e \u0440\u0438\u043b\u043c \u0432\u044b\u0431\u0440\u0430\u043d \u043f\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044e Enter OutcomeMessageType::RealmSelected(realm) => {             \/\/ \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0440\u0438\u043b\u043c \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u0435\u0441\u0441\u0438\u0438 self.session.lock().unwrap().selected_realm = Some(realm);             \/\/ \u043c\u0435\u043d\u044f\u0435\u043c \u0444\u043b\u0430\u0433 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0440\u0430\u0437\u043c\u043e\u0440\u043e\u0437\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 (\u0441\u043c \u043f\u0443\u043d\u043a\u0442 6) self.client_flags.set(ClientFlags::IN_FROZEN_MODE, false); },         \/\/ ... }; }<\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u0433\u0434\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 <em>\u0437\u0430\u043c\u043e\u0440\u043e\u0437\u043a\u0430<\/em> \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 (\u043f\u0443\u043d\u043a\u0442 1). <\/p>\n<pre><code class=\"rust\">fn handle_queue(&amp;mut self) -> JoinHandle&lt;()> {     \/\/ \u0432\u0441\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u043a\u043b\u043e\u043d\u0438\u0440\u0443\u044e \u0447\u0435\u0440\u0435\u0437 Arc::clone()      \/\/ \u0438\u043c\u0435\u044e\u0442 \u0442\u0438\u043f Arc&lt;Mutex&lt;...>> let input_queue = Arc::clone(&amp;self._input_queue); let output_queue = Arc::clone(&amp;self._output_queue); let session = Arc::clone(&amp;self.session); let reader = Arc::clone(&amp;self._reader); let writer = Arc::clone(&amp;self._writer); let warden_crypt = Arc::clone(&amp;self._warden_crypt); let client_flags = Arc::clone(&amp;self.client_flags); let data_storage = Arc::clone(&amp;self.data_storage);  let income_pipe = self._income_message_pipe.lock().unwrap();     \/\/ \u0432\u0441\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0432 debug panel let mut message_income = income_pipe.message_income.clone();     \/\/ \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u043f\u043e\u043a\u0430\u0437 \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u043d\u0430  let dialog_income = income_pipe.dialog_income.clone();  tokio::spawn(async move { loop { let connected_to_realm = client_flags.lock().unwrap().contains( ClientFlags::IS_CONNECTED_TO_REALM );  let packets = input_queue.lock().unwrap().pop_front();  if packets.is_some() { for packet in packets.unwrap() { let processors = match connected_to_realm { true => Self::get_realm_processors(), false => Self::get_login_processors(), };  let mut handler_input = HandlerInput { session: Arc::clone(&amp;session), data: Some(&amp;packet), data_storage: Arc::clone(&amp;data_storage), message_income: message_income.clone(), dialog_income: dialog_income.clone(), };                      \/\/ \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0445\u044d\u043d\u0434\u043b\u0435\u0440\u043e\u0432 \u0434\u043b\u044f                      \/\/ \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043e\u043f\u043a\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u043c \u0438\u0437 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e                      \/\/ \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u0430\u043a\u0435\u0442\u0430 let handler_list = processors .iter() .map(|processor| processor(&amp;mut handler_input)) .flatten() .collect::&lt;Vec&lt;HandlerFunction>>();  for mut handler in handler_list {                         \/\/ \u043a\u0430\u0436\u0434\u044b\u0439 \u0445\u044d\u043d\u0434\u043b\u0435\u0440 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043e\u0434\u043d\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 HandlerOutput match handler(&amp;mut handler_input) { Ok(output) => { match output { HandlerOutput::Data((opcode, header, body)) => { \/\/ ... }, HandlerOutput::ConnectionRequest(host, port) => { \/\/ ... }, HandlerOutput::UpdateState(state) => { \/\/ ... },                                     \/\/ \u044d\u0442\u043e\u0442 \u0442\u0438\u043f \u043e\u0442\u0432\u0435\u0442\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043c\u043e\u0440\u043e\u0437\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443                                     \/\/ \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 (\u0441\u043c. \u043f\u0443\u043d\u043a\u0442 1) HandlerOutput::Freeze => { client_flags.lock().unwrap().set( ClientFlags::IN_FROZEN_MODE, true );  loop { let frozen_mode = client_flags .lock() .unwrap() .contains(ClientFlags::IN_FROZEN_MODE);                                              \/\/ \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0444\u043b\u0430\u0433 \u0433\u0434\u0435-\u0442\u043e \u0438\u0437\u0432\u043d\u0435                                             \/\/ \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 - \u044d\u0442\u043e \u0442\u0430\u0441\u043a handle_ui_output (\u0441\u043c. \u043f\u0443\u043d\u043a\u0442 6) if !frozen_mode { break; }  sleep(Duration::from_millis(WRITE_TIMEOUT)).await; } }, HandlerOutput::Void => {}, }; }, Err(err) => { message_income.send_error_message(err.to_string()); }, };  sleep(Duration::from_millis(WRITE_TIMEOUT)).await; } } } else { sleep(Duration::from_millis(WRITE_TIMEOUT)).await; } } }) }<\/code><\/pre>\n<p>\u041d\u0430 \u0447\u0435\u043c \u0435\u0449\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f, \u0442\u0430\u043a \u044d\u0442\u043e \u043d\u0430 \u043d\u044e\u0430\u043d\u0441\u0430\u0445 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f UI \u0442\u0430\u0441\u043a\u043e\u0432. \u0412\u044b \u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430 \u0437\u0430\u043c\u0435\u0442\u0438\u043b\u0438, \u0447\u0442\u043e \u044f \u0438\u0445 \u0441\u043e\u0437\u0434\u0430\u044e \u0447\u0435\u0440\u0435\u0437 <code>tokio::task::spawn_blocking()<\/code> &#8212; \u0438 \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0430\u043a. \u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442, \u0447\u0442\u043e \u0442\u0430\u0441\u043a \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d <strong>\u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435<\/strong>, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043e\u043d \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u0442\u0430\u0441\u043a\u0438 \u0438 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u043c\u0438. \u0418\u043b\u0438, \u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0442\u0430\u043a\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u044b\u0439 \u043e\u0442\u043a\u043b\u0438\u043a \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\/\u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<h2>\u041f\u0440\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434<\/h2>\n<p>\u041a\u043e\u0433\u0434\u0430 \u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u043b \u0441\u0432\u043e\u0439 \u043f\u0443\u0442\u044c \u0432 Rust \u043d\u0430 \u0441\u0442\u0435\u0437\u0435 \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438, \u043c\u043d\u0435 \u043f\u043e\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043b\u0438 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043d\u0430 <em>tokio-rs. <\/em>\u0422\u043e\u0433\u0434\u0430 \u044f \u0435\u0449\u0435 \u043d\u0435 \u0432\u0434\u0430\u0432\u0430\u043b\u0441\u044f \u0432 \u0434\u0435\u0442\u0430\u043b\u0438 \u0438 \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u044d\u0442\u043e \u0445\u043e\u0440\u043e\u0448\u0438\u0439 \u043f\u043e\u0432\u043e\u0434 \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443. \u041d\u043e, \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u043d\u0435\u0442. \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044f, \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435, \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043b \u0432\u0441\u0435 \u043e\u0448\u0438\u0431\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 <em>tokio-rs<\/em>.<\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e tokio-rs &#8212; \u044d\u0442\u043e \u0442\u0430\u043a\u043e\u0439 \u0440\u0430\u043d\u0442\u0430\u0439\u043c (<em>runtime<\/em>) \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430. \u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u044b \u0438\u043b\u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439, \u0435\u0441\u043b\u0438 \u0432\u044b \u0432\u0438\u0434\u0438\u0442\u0435 \u0432 \u044d\u0442\u043e\u043c \u043d\u0443\u0436\u0434\u0443. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u0441\u0435 \u0442\u0430\u0441\u043a\u0438 \u0432 tokio \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435, \u043d\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0432 \u0444\u0438\u0447\u0443 (feature) \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c &#171;rt-multi-thread&#187;, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e, <strong>\u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438<\/strong>, \u0442\u0430\u0441\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u0430\u0445.<\/p>\n<p><strong>\u041f\u0435\u0440\u0432\u043e\u0439<\/strong> \u043c\u043e\u0435\u0439 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 \u0431\u044b\u043b\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 async \u0432\u0435\u0437\u0434\u0435. \u0414\u0430\u0436\u0435 \u0442\u0430\u043c, \u0433\u0434\u0435 \u044d\u0442\u043e \u043d\u0435 \u043d\u0443\u0436\u043d\u043e. \u0412\u0441\u0435 \u043c\u043e\u0438 \u0442\u0430\u0441\u043a\u0438 \u0441\u0442\u0430\u043b\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438, \u043d\u043e\u0432\u044b\u0435 \u0442\u0430\u0441\u043a\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u043b\u0438\u0441\u044c \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435. \u0422\u0438\u043f\u0438\u0447\u043d\u044b\u0439 \u0442\u0430\u0441\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"rust\">async fn handle_ai(&amp;mut self) -> JoinHandle&lt;()> { let session = Arc::clone(&amp;self.session); let data_storage = Arc::clone(&amp;self.data_storage); let output_queue = Arc::clone(&amp;self._output_queue);  let mut movement_ai = MovementAI::new();  tokio::spawn(async move { loop { movement_ai.manage(AIManagerInput { session: Arc::clone(&amp;session), data_storage: Arc::clone(&amp;data_storage), output_queue: Arc::clone(&amp;output_queue), }).await;  sleep(Duration::from_millis(WRITE_TIMEOUT)).await; } }) }  \/\/ \u0434\u0430\u043b\u0435\u0435 \u0442\u0430\u0441\u043a\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u0438\u0441\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a join_all(vec![ self.handle_ui_render().await, self.handle_ui_input().await, self.handle_ui_output().await, self.handle_ai().await, self.handle_queue().await, self.handle_read().await, self.handle_write().await, ]).await;<\/code><\/pre>\n<p>\u041f\u043e\u0441\u0442\u0430\u0440\u0430\u0439\u0442\u0435\u0441\u044c \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u0442\u044c, \u043a\u0430\u043a\u0438\u0435 \u0432 \u043a\u043e\u0434\u0435 \u0432\u044b\u0448\u0435 \u043e\u0448\u0438\u0431\u043a\u0438.<\/p>\n<details class=\"spoiler\">\n<summary>\u0412\u043e\u0442 \u043a\u0430\u043a\u0438\u0435<\/summary>\n<div class=\"spoiler__content\">\n<p><code>async<\/code> \u0432 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 &#8212; \u043d\u0435 \u043d\u0443\u0436\u0435\u043d, \u0442\u0430\u043a \u043a\u0430\u043a \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434 \u043f\u0440\u0438\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u0442\u043e\u043b\u044c\u043a\u043e \u0432 \u0442\u0435\u043b\u0435 \u0431\u043b\u043e\u043a\u0430 async, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u0442\u0441\u044f \u0432 <code>tokio::spawn<\/code>, \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0432\u044b\u0437\u043e\u0432 \u0444\u0443\u043d\u043a\u0446\u0438\u0439 \u0432 join_all \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0431\u0435\u0437 await, \u0442.\u043a. \u0442\u0430\u043c \u043d\u0435\u0447\u0435\u0433\u043e \u044d\u0432\u044d\u0439\u0442\u0438\u0442\u044c.<\/p>\n<p>\u0422.\u0435., \u0433\u0440\u0443\u0431\u043e \u0433\u043e\u0432\u043e\u0440\u044f, \u043a\u043e\u0434 \u0432\u044b\u0448\u0435 &#8212; \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u0435\u043d.<\/p>\n<\/div>\n<\/details>\n<p><strong>\u0412\u0442\u043e\u0440\u0430\u044f<\/strong> \u043e\u0448\u0438\u0431\u043a\u0430 \u0431\u044b\u043b\u0430 \u0441\u0435\u0440\u044c\u0435\u0437\u043d\u0435\u0435 &#8212; \u0438 \u043f\u0440\u0438\u0432\u0435\u043b\u0430 \u043a \u0434\u044d\u0434\u043b\u043e\u043a\u0430\u043c (deadlock). \u0412 \u043f\u043e\u0433\u043e\u043d\u0435 \u0437\u0430 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u044c\u044e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c mutex \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f <em>\u0441\u043e\u0432\u043c\u0435\u0441\u0442\u043d\u043e\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430 <\/em>(Shared Ownership) \u043a \u0432\u043d\u0435\u0448\u043d\u0438\u043c \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u043c \u044f \u0441\u0442\u0430\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <code>tokio::sync::mutex<\/code> . \u0412 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 (\u0438\u0437-\u0437\u0430 \u0433\u043e\u043d\u043a\u0438 \u0430\u043a\u0430 race condition) \u043f\u043e\u043f\u0430\u043b \u0432 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0439, \u043a\u043e\u0433\u0434\u0430 \u043a\u0430\u043a\u043e\u0439-\u043d\u0438\u0431\u0443\u0434\u044c <code>client_flags<\/code> \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u0438\u0437 \u0442\u0430\u0441\u043a\u043e\u0432 \u0438 \u043d\u0435 \u0434\u0430\u0435\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u0434\u0440\u0443\u0433\u043e\u043c\u0443 \u0442\u0430\u0441\u043a\u0443, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0437\u0430\u0432\u0438\u0441\u0438\u0442 \u043e\u0442 \u0438\u0441\u043a\u043e\u043c\u043e\u0433\u043e. \u0422\u0438\u043f\u0438\u0447\u043d\u044b\u0439 \u0434\u044d\u0434\u043b\u043e\u043a \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0432\u043e\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"rust\">async fn handle_queue(&amp;mut self) -> JoinHandle&lt;()> { \/\/ ...  tokio::spawn(async move { loop { let connected_to_realm = client_flags.lock().unwrap().contains( ClientFlags::IS_CONNECTED_TO_REALM );             \/\/ \u0434\u044d\u0434\u043b\u043e\u043a \u0437\u0434\u0435\u0441\u044c if let Some(packets) = input_queue.lock().await.pop_front() { for packet in packets.unwrap() { \/\/ ...  for mut handler in handler_list { match handler(&amp;mut handler_input) { Ok(output) => { match output { HandlerOutput::Data((opcode, header, body)) => {}, HandlerOutput::ConnectionRequest(host, port) => {}, HandlerOutput::UpdateState(state) => {}, HandlerOutput::Freeze => {}, HandlerOutput::Void => {}, }; }, Err(err) => {}, };  sleep(Duration::from_millis(WRITE_TIMEOUT)).await; } } } else { sleep(Duration::from_millis(WRITE_TIMEOUT)).await; } } }) }<\/code><\/pre>\n<details class=\"spoiler\">\n<summary>\u0414\u0435\u0442\u0430\u043b\u0438 \u0437\u0434\u0435\u0441\u044c<\/summary>\n<div class=\"spoiler__content\">\n<p>\u0414\u044d\u0434\u043b\u043e\u043a \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0435 10. <code>input_queue<\/code> \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u0435\u0442\u0441\u044f \u043d\u0430 \u0432\u0440\u0435\u043c\u044f \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u043b\u043e\u043a\u0430 if. \u0412\u0430\u0440\u0438\u0430\u043d\u0442 \u0440\u0435\u0448\u0435\u043d\u0438\u044f &#8212; \u0432\u044b\u043d\u0435\u0441\u0442\u0438 <code>input_queue.lock().await.pop_front()<\/code> \u0432 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u0443\u044e. <\/p>\n<p>\u041d\u043e \u043b\u0443\u0447\u0448\u0435 &#8212; \u043d\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c (\u043f\u043e \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438) <code>tokio::sync::mutex<\/code>\u0432\u043e\u043e\u0431\u0449\u0435. \u0412 \u0441\u0430\u043c\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 tokio-rs <a href=\"https:\/\/docs.rs\/tokio\/latest\/tokio\/sync\/struct.Mutex.html#which-kind-of-mutex-should-you-use\" rel=\"noopener noreferrer nofollow\">\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u0443\u0435\u0442\u0441\u044f <\/a>\u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 mutex \u0441 \u0443\u043c\u043e\u043c (\u043d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0434\u043b\u044f \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u0439 \u0441 \u0431\u0430\u0437\u043e\u0439 \u0434\u0430\u043d\u043d\u044b\u0445), \u0430 \u0432 \u0431\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u0435 \u0441\u043b\u0443\u0447\u0430\u0435\u0432 &#8212; \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c std::sync::mutex (\u0442.\u0435. \u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 mutex \u0438\u0437 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438).<\/p>\n<p>\u0412\u043e\u0431\u0449\u0435\u043c, \u043a\u043b\u0430\u0441\u0441\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u043e\u0433\u0434\u0430 \u0441\u043d\u0430\u0447\u0430\u043b\u0430 <s>\u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043b \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438 \u0438 \u0441\u0434\u0435\u043b\u0430\u043b \u043a\u0430\u043a \u043d\u0430\u0434\u043e<\/s> \u043f\u043e\u043d\u0430\u0441\u0442\u0430\u0432\u0438\u043b \u0432\u0435\u0437\u0434\u0435 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0445 mutex, \u043d\u0430\u0445\u0432\u0430\u0442\u0430\u043b \u0434\u044d\u0434\u043b\u043e\u043a\u043e\u0432, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0441\u043e stackoverflow \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043b \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u044e \u0438, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, <s>\u0433\u0435\u0440\u043e\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u043e\u0444\u0438\u043a\u0441\u0438\u043b<\/s> \u0441\u0434\u0435\u043b\u0430\u043b \u043a\u0430\u043a \u043d\u0430\u0434\u043e.<\/p>\n<\/div>\n<\/details>\n<p>\u041e\u0442\u0434\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043a\u0430\u043a Reader. \u0414\u043e \u043d\u0435\u0434\u0430\u0432\u043d\u0435\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u043d \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"rust\">pub struct Reader {     stream: OwnedReadHalf,     decryptor: Option&lt;Decryptor>,     warden_crypt: Arc&lt;Mutex&lt;Option&lt;WardenCrypt>>> }  impl Reader {     pub fn new(reader: OwnedReadHalf) -> Self {         Self {             stream: reader,             decryptor: None,             warden_crypt: Arc::new(Mutex::new(None))         }     }      pub fn init(&amp;mut self, session_key: &amp;[u8], warden_crypt: Arc&lt;Mutex&lt;Option&lt;WardenCrypt>>>) {         self.decryptor = Some(Decryptor::new(session_key));         self.warden_crypt = warden_crypt;     }      pub async fn read(&amp;mut self) -> Result&lt;Vec&lt;Vec&lt;u8>>, Error> {         let mut buffer = [0u8; 65536];         \/\/ \u0437\u0434\u0435\u0441\u044c \u043f\u0440\u043e\u0431\u043b\u0435\u043c\u0430, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u0439 read         match self.stream.read(&amp;mut buffer).await {             Ok(bytes_count) => {                 let result = match self.decryptor.as_mut() {                     Some(decryptor) => {                         let warden_crypt = &amp;mut *self.warden_crypt.lock().await;                          Self::parse_packets(                             buffer[..bytes_count].to_vec(),                             decryptor,                             warden_crypt.as_mut().unwrap(),                         )                     },                     _ => {                         vec![buffer[..bytes_count].to_vec()]                     },                 };                  Ok(result)             },             Err(err) => {},         }     } }<\/code><\/pre>\n<p>\u0410\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 <code>.read()<\/code> \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0435 24 \u0432\u044b\u0448\u0435 \u0441\u0442\u0430\u043b \u0442\u043e\u0436\u0435 \u0441\u0432\u043e\u0435\u0433\u043e \u0440\u043e\u0434\u0430 \u0431\u043b\u043e\u043a\u0435\u0440\u043e\u043c, \u043a\u043e\u0433\u0434\u0430 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043c\u043d\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u0438\u043b\u043e\u0441\u044c \u0438\u0433\u0440\u0430\u0442\u044c\u0441\u044f \u0441 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0435\u043c <code>READ_TIMEOUT<\/code> , \u0447\u0442\u043e\u0431\u044b \u043a\u043e\u0434 \u0440\u0430\u0431\u043e\u0442\u0430\u043b. \u042f \u0434\u0443\u043c\u0430\u043b, \u0447\u0442\u043e \u043f\u0440\u0438\u0447\u0438\u043d\u0430 &#8212; \u0432 \u043f\u0438\u043d\u0433\u0435, \u043f\u043e\u043a\u0430 \u043d\u0435 \u043e\u0442\u0440\u0435\u0444\u0430\u043a\u0442\u043e\u0440\u0438\u043b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0438 \u0437\u0430\u043c\u0435\u043d\u0438\u043b, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u0439 <code>.read()<\/code> \u043d\u0430 \u043d\u0435\u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0449\u0438\u0439 <code>.try_read()<\/code> :<\/p>\n<pre><code class=\"rust\">pub fn read(&amp;mut self) -> Result&lt;Vec&lt;Vec&lt;u8>>, Error> { let mut buffer = [0u8; 65536];  match self.stream.try_read(&amp;mut buffer) { Ok(bytes_count) => { let result = match self.decryptor.as_mut() { \/\/ ... };  Ok(result) }, Err(err) => { \/\/ ... }, } }<\/code><\/pre>\n<p>\u043f\u043e\u0441\u043b\u0435 \u044d\u0442\u043e\u0433\u043e \u0444\u0438\u043a\u0441\u0430 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u043b\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 (\u0441 \u0443\u0447\u0435\u0442\u043e\u043c, \u0447\u0442\u043e \u043d\u0430 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u0441\u0435\u0440\u0432\u0435\u0440\u0430\u0445 READ_TIMEOUT \u0431\u044b\u043b \u0440\u0430\u0432\u0435\u043d 250-300).<\/p>\n<h2>\u0418\u0442\u043e\u0433\u043e<\/h2>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0438\u0437\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u0442 \u0438\u0437\u0431\u044b\u0442\u043e\u0447\u043d\u043e\u0433\u043e async\/await \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0441\u0442\u0430\u043b\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u0431\u044b\u0441\u0442\u0440\u0435\u0435 \u0438 \u043f\u0440\u0435\u0434\u0441\u043a\u0430\u0437\u0443\u0435\u043c\u0435\u0435. \u0421 \u043f\u043e\u0437\u0438\u0446\u0438\u0438 \u0441\u0432\u043e\u0435\u0433\u043e \u043e\u043f\u044b\u0442\u0430 \u044f \u0431\u044b \u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c async\/await \u0441 \u0443\u043c\u043e\u043c, \u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u0432\u043d\u0438\u043c\u0430\u0442\u0435\u043b\u044c\u043d\u043e \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442\u044c \u043a \u0432\u044b\u0431\u043e\u0440\u0443 mutex (tokio-rs \u0438\u043b\u0438 \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0430\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430).<\/p>\n<p>\u041e\u0434\u043d\u0430 \u0438\u0437 \u0441\u043b\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439, \u0441 \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u044f \u0441\u0442\u043e\u043b\u043a\u043d\u0443\u043b\u0441\u044f \u043d\u0430 \u044d\u0442\u0430\u043f\u0435 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 &#8212; \u043e\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0438\u0435 \u043c\u0435\u0441\u0442\u0430\u043c\u0438 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e\u0439 \u0434\u043e\u043a\u0443\u043c\u0435\u043d\u0442\u0430\u0446\u0438\u0438. \u0412\u0437\u044f\u0442\u044c \u0442\u043e\u0442 \u0436\u0435 tui-rs, \u0431\u044b\u043b\u043e \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u0447\u0442\u043e Layout \u043c\u043e\u0436\u043d\u043e \u0434\u0440\u043e\u0431\u0438\u0442\u044c \u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0447\u0430\u0441\u0442\u0438 \u0432 \u0434\u0440\u0443\u0433\u043e\u043c Layout, \u043f\u043e\u043a\u0430 \u044f \u043d\u0435 \u043d\u0430\u0448\u0435\u043b \u043a\u0443\u0441\u043e\u043a \u043a\u043e\u0434\u0430 \u0441 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u043c \u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u043f\u0440\u043e\u0435\u043a\u0442\u0435 github. \u0418\u043b\u0438 \u0431\u044b\u043b\u043e \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u043e, \u043a\u0430\u043a \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u043d\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u043d\u043e \u043f\u0435\u0440\u0435\u043a\u0440\u044b\u0432\u0430\u043b\u043e \u0447\u0430\u0441\u0442\u044c \u0443\u0436\u0435 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 (\u043d\u0443\u0436\u043d\u043e \u0440\u0435\u043d\u0434\u0435\u0440\u0438\u0442\u044c \u0432\u0438\u0434\u0436\u0435\u0442 <a href=\"https:\/\/docs.rs\/tui\/latest\/tui\/widgets\/struct.Clear.html\" rel=\"noopener noreferrer nofollow\">Clear<\/a>).<\/p>\n<p>\u041f\u043e\u044d\u0442\u043e\u043c\u0443, \u044f \u0431\u044b \u0445\u043e\u0442\u0435\u043b, \u0447\u0442\u043e\u0431\u044b <a href=\"https:\/\/github.com\/idewave\/idewave-cli\" rel=\"noopener noreferrer nofollow\">\u043c\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442<\/a>, \u0432 \u0447\u0430\u0441\u0442\u043d\u043e\u0441\u0442\u0438, \u043c\u043e\u0433 \u0431\u044b\u0442\u044c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d \u0432 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432: <a href=\"https:\/\/github.com\/idewave\/idewave-cli\/blob\/primary\/src\/ui\/mod.rs#L137\" rel=\"noopener noreferrer nofollow\">\u0440\u0430\u0431\u043e\u0442\u044b \u0441\u043e \u0441\u043b\u043e\u0436\u043d\u044b\u043c\u0438 Layout<\/a>, <a href=\"https:\/\/github.com\/idewave\/idewave-cli\/blob\/primary\/src\/ui\/realm_modal.rs#L131\" rel=\"noopener noreferrer nofollow\">\u043d\u044e\u0430\u043d\u0441\u043e\u0432 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u043c\u043e\u0434\u0430\u043b\u043e\u043a<\/a> \u0438\u043b\u0438 \u043f\u0440\u0438\u043c\u0435\u0440\u0430, \u043a\u0430\u043a \u043c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c <a href=\"https:\/\/github.com\/idewave\/idewave-cli\/blob\/primary\/src\/client\/mod.rs#L184\" rel=\"noopener noreferrer nofollow\">\u0432\u0432\u043e\u0434 \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b<\/a> \u0432 \u043f\u043e\u043b\u043d\u043e\u0446\u0435\u043d\u043d\u043e\u043c \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438.<\/p>\n<p>\u0422\u0430\u043a \u0436\u0435 \u044f \u043d\u0430\u0434\u0435\u044e\u0441\u044c, \u0447\u0442\u043e \u044d\u0442\u0430 \u0441\u0442\u0430\u0442\u044c\u044f \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u0432\u0430\u043c \u0438\u0437\u0431\u0435\u0436\u0430\u0442\u044c \u0434\u044d\u0434\u043b\u043e\u043a\u043e\u0432.<\/p>\n<p>\u0418, \u043a\u043e\u043d\u0435\u0447\u043d\u043e, \u044f \u0431\u0443\u0434\u0443 \u0440\u0430\u0434 \u0432\u0441\u0435\u043c, \u043a\u0442\u043e \u0437\u0430\u0445\u043e\u0447\u0435\u0442 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0432\u043a\u043b\u0430\u0434 \u0432 \u043c\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442: <a href=\"https:\/\/github.com\/idewave\/idewave-cli\" rel=\"noopener noreferrer nofollow\">https:\/\/github.com\/idewave\/idewave-cli<\/a><\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"v-portal\" style=\"display:none;\"><\/div>\n<\/div>\n<p> <!----> <\/p>\n<div class=\"tm-article-poll\">\n<div class=\"tm-notice tm-article-poll__notice tm-notice_positive\"><!----> <\/p>\n<div class=\"tm-notice__inner\"><!----> <\/p>\n<div data-test-id=\"notice-content\" class=\"tm-notice__content\"><span>\u0422\u043e\u043b\u044c\u043a\u043e \u0437\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043c\u043e\u0433\u0443\u0442 \u0443\u0447\u0430\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0432 \u043e\u043f\u0440\u043e\u0441\u0435. <a rel=\"nofollow\" href=\"\/kek\/v1\/auth\/habrahabr\/?back=\/ru\/post\/681556\/&#038;hl=ru\">\u0412\u043e\u0439\u0434\u0438\u0442\u0435<\/a>, \u043f\u043e\u0436\u0430\u043b\u0443\u0439\u0441\u0442\u0430.<\/span><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__header\">\u0427\u0435\u0433\u043e \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 \u0432 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435?<\/div>\n<div class=\"tm-article-poll__answers\">\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">             0%           <\/span> <span class=\"tm-article-poll__answer-label\">\u041e\u0442\u043b\u0438\u0447\u043d\u0430\u044f \u0441\u0442\u0430\u0442\u044c\u044f, \u0432\u0441\u0435\u0433\u043e \u0445\u0432\u0430\u0442\u0430\u0435\u0442, \u0431\u0443\u0434\u0435\u0442 \u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u043e \u043f\u043e\u0447\u0438\u0442\u0430\u0442\u044c \u043d\u043e\u0432\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b \u043f\u043e \u0442\u0435\u043c\u0435!<\/span> <span class=\"tm-article-poll__answer-votes\">             0           <\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width:0%;\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">             0%           <\/span> <span class=\"tm-article-poll__answer-label\">\u0422\u043e\u0447\u043d\u043e\u0441\u0442\u0438 \u0438\u0437\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043d\u0435 \u0445\u0432\u0430\u0442\u0430\u0435\u0442 (\u0442\u0435\u043a\u0441\u0442 \u043c\u0435\u0441\u0442\u0430\u043c\u0438 \u0442\u0440\u0443\u0434\u043d\u043e \u0432\u043e\u0441\u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0442\u044c)<\/span> <span class=\"tm-article-poll__answer-votes\">             0           <\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width:0%;\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">             0%           <\/span> <span class=\"tm-article-poll__answer-label\">\u041c\u0430\u043b\u043e \u043a\u0430\u0440\u0442\u0438\u043d\u043e\u043a<\/span> <span class=\"tm-article-poll__answer-votes\">             0           <\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width:0%;\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">             0%           <\/span> <span class=\"tm-article-poll__answer-label\">\u041d\u0438\u0437\u043a\u0438\u0439 \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u0438\u0439 \u0443\u0440\u043e\u0432\u0435\u043d\u044c \u0441\u0442\u0430\u0442\u044c\u0438 (\u043e\u0447\u0435\u043d\u044c \u043c\u0430\u043b\u043e Rust)<\/span> <span class=\"tm-article-poll__answer-votes\">             0           <\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width:0%;\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">             0%           <\/span> <span class=\"tm-article-poll__answer-label\">\u041c\u0430\u043b\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 (\u043d\u0443\u0436\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 \u043a\u043e\u0434\u0430)<\/span> <span class=\"tm-article-poll__answer-votes\">             0           <\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width:0%;\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent\">             0%           <\/span> <span class=\"tm-article-poll__answer-label\">\u041c\u0430\u043b\u043e \u043f\u0440\u0438\u043c\u0435\u0440\u043e\u0432 (\u043d\u0443\u0436\u043d\u043e \u0431\u043e\u043b\u044c\u0448\u0435 \u0440\u0430\u0437\u0431\u043e\u0440\u043e\u0432 \u0441\u043b\u043e\u0436\u043d\u044b\u0445 \u0441\u0438\u0442\u0443\u0430\u0446\u0438\u0439)<\/span> <span class=\"tm-article-poll__answer-votes\">             0           <\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress\" style=\"width:0%;\"><\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__answer\">\n<div class=\"tm-article-poll__answer-data\"><span class=\"tm-article-poll__answer-percent tm-article-poll__answer-percent_winning\">             0%           <\/span> <span class=\"tm-article-poll__answer-label\">\u041d\u0435 \u0447\u0438\u0442\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u044e<\/span> <span class=\"tm-article-poll__answer-votes\">             0           <\/span><\/div>\n<div class=\"tm-article-poll__answer-bar\">\n<div class=\"tm-article-poll__answer-progress tm-article-poll__answer-progress_winning\" style=\"width:0%;\"><\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"tm-article-poll__stats\">        \u041d\u0438\u043a\u0442\u043e \u0435\u0449\u0435 \u043d\u0435 \u0433\u043e\u043b\u043e\u0441\u043e\u0432\u0430\u043b.          \u0412\u043e\u0437\u0434\u0435\u0440\u0436\u0430\u043b\u0438\u0441\u044c 4 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.      <\/div>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/681556\/\"> https:\/\/habr.com\/ru\/post\/681556\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>\u0421 \u0432\u044b\u0445\u043e\u0434\u043e\u043c \u0432\u0435\u0440\u0441\u0438\u0438 1.0.1 \u044f \u0440\u0435\u0448\u0438\u043b \u043e\u0441\u0432\u0435\u0442\u0438\u0442\u044c \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0430\u0441\u043f\u0435\u043a\u0442\u044b \u0442\u0435\u0445\u043d\u0438\u0447\u0435\u0441\u043a\u043e\u0439 \u0441\u0442\u043e\u0440\u043e\u043d\u044b <a href=\"https:\/\/github.com\/idewave\/idewave-cli\" rel=\"noopener noreferrer nofollow\">\u043c\u043e\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430<\/a>. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <em>tui-rs<\/em> \u0438 \u043f\u0440\u043e \u043d\u044e\u0430\u043d\u0441\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438 <em>tokio-rs<\/em>, \u0430 \u0442\u0430\u043a \u0436\u0435 \u043f\u043e\u0441\u0442\u0430\u0440\u0430\u044e\u0441\u044c \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u0447\u0442\u043e \u0436\u0435 \u0431\u044b\u043b\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e \u0438 \u043f\u043e\u0447\u0435\u043c\u0443 \u0442\u0430\u043a, \u043a\u0430\u043a \u0431\u044b\u043b\u043e \u0440\u0430\u043d\u044c\u0448\u0435 \u0434\u0435\u043b\u0430\u0442\u044c \u043d\u0435 \u043d\u0430\u0434\u043e. \u0414\u043e\u0431\u0440\u043e \u043f\u043e\u0436\u0430\u043b\u043e\u0432\u0430\u0442\u044c \u0432 \u0441\u0442\u0430\u0442\u044c\u044e &#8212; \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e, \u043a\u043e\u043c\u0443-\u0442\u043e \u043e\u043d\u0430 \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430 \u0442\u0435\u0440\u043d\u0438\u0441\u0442\u043e\u043c \u043f\u0443\u0442\u0438 \u043f\u043e\u0433\u0440\u0443\u0436\u0435\u043d\u0438\u044f (\u0438\u043b\u0438 \u0432\u043e\u0441\u0445\u043e\u0436\u0434\u0435\u043d\u0438\u044f) \u0432 Rust.<\/p>\n<hr\/>\n<p>\u041c\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442 \u043f\u0440\u0435\u0434\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0438\u0437 \u0441\u0435\u0431\u044f \u043a\u043e\u043d\u0441\u043e\u043b\u044c\u043d\u044b\u0439 \u043a\u043b\u0438\u0435\u043d\u0442 \u0434\u043b\u044f \u0438\u0433\u0440\u044b World of Warcraft (\u043d\u043e \u0441\u043b\u0443\u0436\u0438\u0442 \u0434\u043b\u044f \u0434\u0440\u0443\u0433\u0438\u0445 \u0446\u0435\u043b\u0435\u0439 \u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u044d\u0442\u043e &#8212; \u043d\u0435 \u0442\u043e \u0436\u0435 \u0441\u0430\u043c\u043e\u0435). \u041f\u043e\u0441\u043b\u0435 \u043d\u0435\u0434\u0430\u0432\u043d\u0435\u0433\u043e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u044f \u043e\u043d \u043e\u0431\u0437\u0430\u0432\u0435\u043b\u0441\u044f \u0442\u0435\u043a\u0441\u0442\u043e\u0432\u044b\u043c \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u043e\u043c \u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u0441\u0442\u0430\u043b \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u044e\u0437\u0430\u0431\u0435\u043b\u044c\u043d\u0435\u0435.<\/p>\n<figure class=\"full-width\"><figcaption>\u041e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u0435 \u043e\u043f\u043a\u043e\u0434\u043e\u0432 \u043f\u0430\u043a\u0435\u0442\u043e\u0432, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043d\u044b\u0445 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/figcaption><\/figure>\n<p>\u041d\u043e \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043e\u0431\u044a\u0435\u043c\u043d\u043e\u0439 \u0437\u0430\u0434\u0430\u0447\u0435\u0439. \u041d\u0430\u0447\u043d\u0443 \u0441 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u044f \u0438\u0437\u043d\u0430\u0447\u0430\u043b\u044c\u043d\u043e \u0440\u0435\u0448\u0438\u043b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u044e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u0432 \u0432\u0438\u0434\u0435 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0442\u0430\u0441\u043a\u0430 \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043c\u0430\u043a\u0441\u0438\u043c\u0430\u043b\u044c\u043d\u043e \u0438\u043d\u043a\u0430\u043f\u0441\u0443\u043b\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0434, \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0438\u0439\u0441\u044f \u043a UI. \u041d\u0430 \u0442\u0435\u043a\u0443\u0449\u0438\u0439 \u043c\u043e\u043c\u0435\u043d\u0442 \u043c\u043e\u0438 \u0442\u0430\u0441\u043a\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u044e\u0442\u0441\u044f \u0432\u043e\u0442 \u0442\u0430\u043a:<\/p>\n<pre><code class=\"rust\">join_all(vec![ self.handle_ui_render(), self.handle_ui_input(), self.handle_ui_output(),    self.handle_ai(), self.handle_queue(), self.handle_read(), self.handle_write(), ]).await;<\/code><\/pre>\n<p>\u0442\u0430\u0441\u043a\u0438, \u043e\u0442\u043d\u043e\u0441\u044f\u0449\u0438\u0435\u0441\u044f \u043a UI &#8212; \u0438\u0445 \u043f\u043e\u043a\u0430 \u0432\u0441\u0435\u0433\u043e \u0442\u0440\u0438. \u041f\u043e\u043c\u0438\u043c\u043e, \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u043e, \u0442\u0430\u0441\u043a\u0430 \u0434\u043b\u044f \u0440\u0435\u043d\u0434\u0435\u0440\u0430 \u044f \u0441\u043e\u0437\u0434\u0430\u044e \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0442\u0430\u0441\u043a \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u043e\u0431\u044b\u0442\u0438\u0439 \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b \u0438 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0439 \u0442\u0430\u0441\u043a \u0434\u043b\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043e\u0442\u043a\u043b\u0438\u043a\u0430 \u043e\u0442 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430.<\/p>\n<p>\u0422\u0438\u043f\u0438\u0447\u043d\u044b\u0439 \u043f\u0440\u0438\u043c\u0435\u0440, \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442: \u0432 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0435 \u0441\u043e\u0435\u0434\u0438\u043d\u0435\u043d\u0438\u044f \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u043e\u043c \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u044c\u0441\u044f \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0432\u044b\u0431\u043e\u0440. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u0432\u044b\u0431\u043e\u0440 \u0440\u0438\u043b\u043c\u0430 (<em>realm<\/em>) \u0438\u043b\u0438 \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0434\u043b\u044f \u0432\u0445\u043e\u0434\u0430 \u0432 \u043c\u0438\u0440. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u043f\u043e\u043a\u0430\u0437\u0430\u0442\u044c \u043a\u0430\u043a\u043e\u0435-\u043d\u0438\u0431\u0443\u0434\u044c \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u043d\u043e. <\/p>\n<figure class=\"full-width\"><figcaption>\u0412\u044b\u0431\u043e\u0440 \u0440\u0438\u043b\u043c\u0430 \u0438\u0437 \u0441\u043f\u0438\u0441\u043a\u0430 \u0432 \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u043c \u043e\u043a\u043d\u0435<\/figcaption><\/figure>\n<p>\u0417\u0434\u0435\u0441\u044c \u0432\u0441\u0442\u0443\u043f\u0430\u0435\u0442 \u0432 \u0441\u0438\u043b\u0443 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439:<\/p>\n<ol>\n<li>\n<p>\u044f \u0437\u0430\u043c\u043e\u0440\u0430\u0436\u0438\u0432\u0430\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 (\u0445\u043e\u0442\u044f, \u043f\u043e \u043f\u0440\u0435\u0436\u043d\u0435\u043c\u0443 \u0438\u0445 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e \u0438 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u044e \u0432 \u043e\u0447\u0435\u0440\u0435\u0434\u044c)<\/p>\n<\/li>\n<li>\n<p>\u043e\u0442\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u044e \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0435 \u043e\u043a\u043d\u043e \u0441\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u043c \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0435\u0439 \u0438\u043b\u0438 \u0440\u0438\u043b\u043c\u043e\u0432<\/p>\n<\/li>\n<li>\n<p>\u043e\u0436\u0438\u0434\u0430\u044e, \u043f\u043e\u043a\u0430 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u043e \u0441\u043e\u0431\u044b\u0442\u0438\u0435 \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b (\u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 &#8212; \u043d\u0430\u0436\u0430\u0442\u0438\u0435 \u0441\u0442\u0440\u0435\u043b\u043a\u0438 \u0432\u043d\u0438\u0437\/\u0432\u0432\u0435\u0440\u0445)<\/p>\n<\/li>\n<li>\n<p>\u043f\u0435\u0440\u0435\u0440\u0438\u0441\u043e\u0432\u044b\u0432\u0430\u044e \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441, \u043d\u043e \u0443\u0436\u0435 \u0441 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u043c \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u043c \u0432 \u0441\u043f\u0438\u0441\u043a\u0435<\/p>\n<\/li>\n<li>\n<p>\u0432 \u043a\u043e\u043d\u0446\u0435-\u043a\u043e\u043d\u0446\u043e\u0432, \u0432\u044b\u0431\u043e\u0440 \u0441\u0434\u0435\u043b\u0430\u043d, \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044f \u043d\u0430\u0436\u0430\u0442\u0438\u0435 Enter, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u043f\u043e\u0432\u0435\u0449\u0435\u043d\u0438\u0435 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u043e \u0441\u0434\u0435\u043b\u0430\u043d\u043d\u043e\u043c \u0432\u044b\u0431\u043e\u0440\u0435<\/p>\n<\/li>\n<li>\n<p>\u0438, \u043d\u0430\u043a\u043e\u043d\u0435\u0446, \u044f \u0440\u0430\u0437\u043c\u043e\u0440\u0430\u0436\u0438\u0432\u0430\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432<\/p>\n<\/li>\n<\/ol>\n<p>\u0412 \u043a\u043e\u0434\u0435 \u044d\u0442\u043e \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"rust\">\/\/ \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0437\u0434\u0435\u0441\u044c (\u0441\u043c \u043f\u0443\u043d\u043a\u0442 3 \u0438 5) fn handle_ui_input(&amp;mut self) -> JoinHandle&lt;()> { let income_pipe = self._income_message_pipe.lock().unwrap();     \/\/ \u0441\u044e\u0434\u0430 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0432\u0441\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u0441 \u043a\u043b\u0430\u0432\u0438\u0430\u0442\u0443\u0440\u044b let event_income = income_pipe.event_income.clone();  tokio::task::spawn_blocking(move || { let mut ui_input = UIInput::new(event_income);  loop { ui_input.handle(); } }) }  \/\/ \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u043e\u0432 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u0437\u0434\u0435\u0441\u044c (\u0441\u043c \u043f\u0443\u043d\u043a\u0442 2 \u0438 4) fn handle_ui_render(&amp;mut self) -> JoinHandle&lt;()> { \/\/ ... let outcome_message_pipe = self._outcome_message_pipe.lock().unwrap();     \/\/ \u043e\u0442\u043a\u043b\u0438\u043a \u043e\u0442 UI \u043e\u0442 \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u044b\u0445 \u043e\u043a\u043e\u043d let dialog_outcome = pipe.dialog_outcome.clone();     \/\/ ...  tokio::task::spawn_blocking(move || {         \/\/ UI renderer, \u043e\u0442\u0432\u0435\u0447\u0430\u044e\u0449\u0438\u0439 \u0437\u0430 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0443 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430 let mut ui = UI::new( CrosstermBackend::new(std::io::stdout()), UIOutputOptions { dialog_outcome, \/\/ ... }, );  loop { \/\/ ...  ui.render(UIRenderOptions {                 \/\/ \u0432\u0441\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0441\u043e\u0431\u044b\u0442\u0438\u044f \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u044e\u0442\u0441\u044f \u0437\u0434\u0435\u0441\u044c message: income_message_pipe.lock().unwrap().recv(), client_flags, }); } }) }  fn handle_ui_output(&amp;mut self) -> JoinHandle&lt;()> { let outcome_message_pipe = Arc::clone(&amp;self._outcome_message_pipe); \/\/ ...  tokio::task::spawn_blocking(move || { loop {             \/\/ \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u0438\u0441\u0445\u043e\u0434\u044f\u0449\u0438\u0439 \u043e\u0442\u043a\u043b\u0438\u043a \u043e\u0442 UI \u0438 \u043e\u0431\u0440\u0430\u0431\u0430\u0442\u044b\u0432\u0430\u0435\u043c, \u0435\u0441\u043b\u0438 \u043e\u043d \u0438\u043c\u0435\u0435\u0442\u0441\u044f if let Ok(message) = outcome_message_pipe.lock().unwrap().recv() { \/\/ ...  let mut ui_output = UIOutput::new(Arc::clone(&amp;session), client_flags);                 \/\/ \u044d\u0442\u0443 \u0441\u0442\u0440\u043e\u043a\u0443 \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0438\u043c \u0447\u0443\u0442\u044c \u043d\u0438\u0436\u0435 ui_output.handle(message); } } }) }<\/code><\/pre>\n<p>\u0412 <code>ui_output.handle(message)<\/code> \u043d\u0430 \u0441\u0442\u0440\u043e\u043a\u0435 57 \u0432\u044b\u0448\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 \u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0441 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0439 \u0447\u0430\u0441\u0442\u044c\u044e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0447\u0435\u0440\u0435\u0437 \u044d\u043b\u0435\u043c\u0435\u043d\u0442\u044b \u043c\u0435\u0436\u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043d\u043e\u0433\u043e \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f (IPC) &#8212; \u0432 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u044d\u0442\u043e <code>session<\/code> , \u0430 \u0442\u0430\u043a \u0436\u0435 \u0447\u0435\u0440\u0435\u0437 \u0444\u043b\u0430\u0433\u0438 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f (\u0441\u043e\u0437\u0434\u0430\u043d\u043d\u044b\u0435 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u043c\u0430\u043a\u0440\u043e\u0441\u0430 <code>bitflags!<\/code> \u0438\u0437 \u043e\u0434\u043d\u043e\u0438\u043c\u0435\u043d\u043d\u043e\u0439 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0438):<\/p>\n<pre><code class=\"rust\">pub fn handle(&amp;mut self, message: OutcomeMessageType) { match message {         \/\/ \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043e\u0442\u043a\u043b\u0438\u043a, \u0447\u0442\u043e \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436 \u0432\u044b\u0431\u0440\u0430\u043d \u043f\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044e Enter OutcomeMessageType::CharacterSelected(character) => {             \/\/ \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u0436\u0430 \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u0435\u0441\u0441\u0438\u0438 self.session.lock().unwrap().me = Some(Player::from(character));             \/\/ \u043c\u0435\u043d\u044f\u0435\u043c \u0444\u043b\u0430\u0433 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0440\u0430\u0437\u043c\u043e\u0440\u043e\u0437\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 (\u0441\u043c \u043f\u0443\u043d\u043a\u0442 6) self.client_flags.set(ClientFlags::IN_FROZEN_MODE, false); },         \/\/ \u043f\u043e\u043b\u0443\u0447\u0438\u043b\u0438 \u043e\u0442\u043a\u043b\u0438\u043a, \u0447\u0442\u043e \u0440\u0438\u043b\u043c \u0432\u044b\u0431\u0440\u0430\u043d \u043f\u043e \u043d\u0430\u0436\u0430\u0442\u0438\u044e Enter OutcomeMessageType::RealmSelected(realm) => {             \/\/ \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u043c \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u044b\u0439 \u0440\u0438\u043b\u043c \u0432 \u043e\u0431\u044a\u0435\u043a\u0442 \u0441\u0435\u0441\u0441\u0438\u0438 self.session.lock().unwrap().selected_realm = Some(realm);             \/\/ \u043c\u0435\u043d\u044f\u0435\u043c \u0444\u043b\u0430\u0433 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0434\u043b\u044f \u0440\u0430\u0437\u043c\u043e\u0440\u043e\u0437\u043a\u0438 \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 (\u0441\u043c \u043f\u0443\u043d\u043a\u0442 6) self.client_flags.set(ClientFlags::IN_FROZEN_MODE, false); },         \/\/ ... }; }<\/code><\/pre>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c, \u0433\u0434\u0435 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442 <em>\u0437\u0430\u043c\u043e\u0440\u043e\u0437\u043a\u0430<\/em> \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 (\u043f\u0443\u043d\u043a\u0442 1). <\/p>\n<pre><code class=\"rust\">fn handle_queue(&amp;mut self) -> JoinHandle&lt;()> {     \/\/ \u0432\u0441\u0435 \u043f\u0435\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u044f \u043a\u043b\u043e\u043d\u0438\u0440\u0443\u044e \u0447\u0435\u0440\u0435\u0437 Arc::clone()      \/\/ \u0438\u043c\u0435\u044e\u0442 \u0442\u0438\u043f Arc&lt;Mutex&lt;...>> let input_queue = Arc::clone(&amp;self._input_queue); let output_queue = Arc::clone(&amp;self._output_queue); let session = Arc::clone(&amp;self.session); let reader = Arc::clone(&amp;self._reader); let writer = Arc::clone(&amp;self._writer); let warden_crypt = Arc::clone(&amp;self._warden_crypt); let client_flags = Arc::clone(&amp;self.client_flags); let data_storage = Arc::clone(&amp;self.data_storage);  let income_pipe = self._income_message_pipe.lock().unwrap();     \/\/ \u0432\u0441\u0435 \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u044b \u0445\u043e\u0442\u0438\u043c \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u0432 debug panel let mut message_income = income_pipe.message_income.clone();     \/\/ \u0434\u043b\u044f \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u043f\u043e\u043a\u0430\u0437 \u043c\u043e\u0434\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043e\u043a\u043d\u0430  let dialog_income = income_pipe.dialog_income.clone();  tokio::spawn(async move { loop { let connected_to_realm = client_flags.lock().unwrap().contains( ClientFlags::IS_CONNECTED_TO_REALM );  let packets = input_queue.lock().unwrap().pop_front();  if packets.is_some() { for packet in packets.unwrap() { let processors = match connected_to_realm { true => Self::get_realm_processors(), false => Self::get_login_processors(), };  let mut handler_input = HandlerInput { session: Arc::clone(&amp;session), data: Some(&amp;packet), data_storage: Arc::clone(&amp;data_storage), message_income: message_income.clone(), dialog_income: dialog_income.clone(), };                      \/\/ \u043a\u0430\u0436\u0434\u044b\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u0440 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0445\u044d\u043d\u0434\u043b\u0435\u0440\u043e\u0432 \u0434\u043b\u044f                      \/\/ \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u043e\u043f\u043a\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u044b \u0438\u0437\u0432\u043b\u0435\u043a\u0430\u043c \u0438\u0437 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0449\u0435\u0433\u043e                      \/\/ \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u0430\u043a\u0435\u0442\u0430 let handler_list = processors .iter() .map(|processor| processor(&amp;mut handler_input)) .flatten() .collect::&lt;Vec&lt;HandlerFunction>>();  for mut handler in handler_list {                         \/\/ \u043a\u0430\u0436\u0434\u044b\u0439 \u0445\u044d\u043d\u0434\u043b\u0435\u0440 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0435\u0442 \u043e\u0434\u043d\u043e \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0438 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 HandlerOutput match handler(&amp;mut handler_input) { Ok(output) => { match output { HandlerOutput::Data((opcode, header, body)) => { \/\/ ... }, HandlerOutput::ConnectionRequest(host, port) => { \/\/ ... }, HandlerOutput::UpdateState(state) => { \/\/ ... },                                     \/\/ \u044d\u0442\u043e\u0442 \u0442\u0438\u043f \u043e\u0442\u0432\u0435\u0442\u0430 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0437\u0430\u043c\u043e\u0440\u043e\u0437\u0438\u0442\u044c \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443                                     \/\/ \u043f\u043e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0445 \u043f\u0430\u043a\u0435\u0442\u043e\u0432 (\u0441\u043c. \u043f\u0443\u043d\u043a\u0442 1) HandlerOutput::Freeze => { client_flags.lock().unwrap().set( ClientFlags::IN_FROZEN_MODE, true );  loop { let frozen_mode = client_flags .lock() .unwrap() .contains(ClientFlags::IN_FROZEN_MODE);                                              \/\/ \u0434\u043b\u044f \u043e\u0442\u043c\u0435\u043d\u044b \u043d\u0443\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0438\u0442\u044c \u0444\u043b\u0430\u0433 \u0433\u0434\u0435-\u0442\u043e \u0438\u0437\u0432\u043d\u0435                                             \/\/ \u0432 \u043d\u0430\u0448\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435 - \u044d\u0442\u043e \u0442\u0430\u0441\u043a handle_ui_output (\u0441\u043c. \u043f\u0443\u043d\u043a\u0442 6) if !frozen_mode { break; }  sleep(Duration::from_millis(WRITE_TIMEOUT)).await; } }, HandlerOutput::Void => {}, }; }, Err(err) => { message_income.send_error_message(err.to_string()); }, };  sleep(Duration::from_millis(WRITE_TIMEOUT)).await; } } } else { sleep(Duration::from_millis(WRITE_TIMEOUT)).await; } } }) }<\/code><\/pre>\n<p>\u041d\u0430 \u0447\u0435\u043c \u0435\u0449\u0435 \u0445\u043e\u0442\u0435\u043b\u043e\u0441\u044c \u0431\u044b \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c\u0441\u044f, \u0442\u0430\u043a \u044d\u0442\u043e \u043d\u0430 \u043d\u044e\u0430\u043d\u0441\u0430\u0445 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f UI \u0442\u0430\u0441\u043a\u043e\u0432. \u0412\u044b \u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430 \u0437\u0430\u043c\u0435\u0442\u0438\u043b\u0438, \u0447\u0442\u043e \u044f \u0438\u0445 \u0441\u043e\u0437\u0434\u0430\u044e \u0447\u0435\u0440\u0435\u0437 <code>tokio::task::spawn_blocking()<\/code> &#8212; \u0438 \u044d\u0442\u043e \u043d\u0435 \u043f\u0440\u043e\u0441\u0442\u043e \u0442\u0430\u043a. \u042d\u0442\u0430 \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442, \u0447\u0442\u043e \u0442\u0430\u0441\u043a \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u043d <strong>\u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435<\/strong>, \u0442\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u043e\u043d \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0434\u0440\u0443\u0433\u0438\u0435 \u0442\u0430\u0441\u043a\u0438 \u0438 \u043d\u0435 \u0431\u0443\u0434\u0435\u0442 \u0431\u043b\u043e\u043a\u0438\u0440\u043e\u0432\u0430\u0442\u044c\u0441\u044f \u0438\u043c\u0438. \u0418\u043b\u0438, \u0432 \u043c\u043e\u0435\u043c \u0441\u043b\u0443\u0447\u0430\u0435, \u0442\u0430\u043a\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u044f \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u0443\u0435\u0442 \u043c\u0433\u043d\u043e\u0432\u0435\u043d\u043d\u044b\u0439 \u043e\u0442\u043a\u043b\u0438\u043a \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430, \u043f\u043e\u0441\u043a\u043e\u043b\u044c\u043a\u0443 \u043f\u0435\u0440\u0435\u0445\u0432\u0430\u0442 \u0441\u043e\u0431\u044b\u0442\u0438\u0439\/\u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u0431\u0443\u0434\u0443\u0442 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u0442\u044c\u0441\u044f \u043d\u0435\u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e \u043e\u0442 \u043e\u0441\u0442\u0430\u043b\u044c\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f.<\/p>\n<h2>\u041f\u0440\u043e \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0439 \u043a\u043e\u0434<\/h2>\n<p>\u041a\u043e\u0433\u0434\u0430 \u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0447\u0438\u043d\u0430\u043b \u0441\u0432\u043e\u0439 \u043f\u0443\u0442\u044c \u0432 Rust \u043d\u0430 \u0441\u0442\u0435\u0437\u0435 \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u0438, \u043c\u043d\u0435 \u043f\u043e\u0440\u0435\u043a\u043e\u043c\u0435\u043d\u0434\u043e\u0432\u0430\u043b\u0438 \u043f\u0435\u0440\u0435\u0439\u0442\u0438 \u043d\u0430 <em>tokio-rs. <\/em>\u0422\u043e\u0433\u0434\u0430 \u044f \u0435\u0449\u0435 \u043d\u0435 \u0432\u0434\u0430\u0432\u0430\u043b\u0441\u044f \u0432 \u0434\u0435\u0442\u0430\u043b\u0438 \u0438 \u0440\u0435\u0448\u0438\u043b, \u0447\u0442\u043e \u044d\u0442\u043e \u0445\u043e\u0440\u043e\u0448\u0438\u0439 \u043f\u043e\u0432\u043e\u0434 \u0438\u0437\u0443\u0447\u0438\u0442\u044c \u043d\u043e\u0432\u0443\u044e \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0443. \u041d\u043e, \u043e\u043a\u0430\u0437\u0430\u043b\u043e\u0441\u044c, \u0447\u0442\u043e \u043d\u0435\u0442. \u041f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u044f, \u043d\u0430\u0432\u0435\u0440\u043d\u043e\u0435, \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u043b \u0432\u0441\u0435 \u043e\u0448\u0438\u0431\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0434\u043e\u043f\u0443\u0441\u0442\u0438\u0442\u044c \u043f\u0440\u0438 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0438 <em>tokio-rs<\/em>.<\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e tokio-rs &#8212; \u044d\u0442\u043e \u0442\u0430\u043a\u043e\u0439 \u0440\u0430\u043d\u0442\u0430\u0439\u043c (<em>runtime<\/em>) \u0434\u043b\u044f \u0437\u0430\u043f\u0443\u0441\u043a\u0430 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u043e\u0433\u043e \u043a\u043e\u0434\u0430. \u041c\u043e\u0436\u043d\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0438 \u0434\u0440\u0443\u0433\u0438\u0435 \u0440\u0430\u043d\u0442\u0430\u0439\u043c\u044b \u0438\u043b\u0438 \u0432\u043e\u043e\u0431\u0449\u0435 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439, \u0435\u0441\u043b\u0438 \u0432\u044b \u0432\u0438\u0434\u0438\u0442\u0435 \u0432 \u044d\u0442\u043e\u043c \u043d\u0443\u0436\u0434\u0443. \u041f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0432\u0441\u0435 \u0442\u0430\u0441\u043a\u0438 \u0432 tokio \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u0432 \u043e\u0434\u043d\u043e\u043c \u043f\u043e\u0442\u043e\u043a\u0435, \u043d\u043e \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u0442\u044c \u043c\u0443\u043b\u044c\u0442\u0438\u043f\u043e\u0442\u043e\u0447\u043d\u043e\u0441\u0442\u044c, \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0438\u0432 \u0444\u0438\u0447\u0443 (feature) \u043f\u043e\u0434 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u0435\u043c &#171;rt-multi-thread&#187;, \u043f\u043e\u0441\u043b\u0435 \u0447\u0435\u0433\u043e, <strong>\u043f\u0440\u0438 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e\u0441\u0442\u0438<\/strong>, \u0442\u0430\u0441\u043a\u0438 \u0431\u0443\u0434\u0443\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c\u0441\u044f \u0432 \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0445 \u043f\u043e\u0442\u043e\u043a\u0430\u0445.<\/p>\n<p><strong>\u041f\u0435\u0440\u0432\u043e\u0439<\/strong> \u043c\u043e\u0435\u0439 \u043e\u0448\u0438\u0431\u043a\u043e\u0439 \u0431\u044b\u043b\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 async \u0432\u0435\u0437\u0434\u0435. \u0414\u0430\u0436\u0435 \u0442\u0430\u043c, \u0433\u0434\u0435 \u044d\u0442\u043e \u043d\u0435 \u043d\u0443\u0436\u043d\u043e. \u0412\u0441\u0435 \u043c\u043e\u0438 \u0442\u0430\u0441\u043a\u0438 \u0441\u0442\u0430\u043b\u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c\u0438, \u043d\u043e\u0432\u044b\u0435 \u0442\u0430\u0441\u043a\u0438 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u043b\u0438\u0441\u044c \u0432 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435. \u0422\u0438\u043f\u0438\u0447\u043d\u044b\u0439 \u0442\u0430\u0441\u043a \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u043b \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a:<\/p>\n<pre><code class=\"rust\">async fn handle_ai(&amp;mut self) -> JoinHandle&lt;()> { let session = Arc::clone(&amp;self.session); let data_storage = Arc::clone(&amp;self.data_storage); let output_queue = Arc::clone(&amp;self._output_queue);  let mut movement_ai = MovementAI::new();  tokio::spawn(async move { loop { movement_ai.manage(AIManagerInput { session: Arc::clone(&amp;session), data_storage: Arc::clone(&amp;data_storage), output_queue: Arc::clone(&amp;output_queue), }).await;  sleep(Duration::from_millis(WRITE_TIMEOUT)).await; } }) }  \/\/ \u0434\u0430\u043b\u0435\u0435 \u0442\u0430\u0441\u043a\u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u043b\u0438\u0441\u044c \u043f\u0440\u0438\u043c\u0435\u0440\u043d\u043e \u0442\u0430\u043a join_all(vec![ self.handle_ui_render().await,<\/code><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-336771","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/336771","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=336771"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/336771\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=336771"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=336771"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=336771"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}