<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>Титов Климентий</title><generator>teletype.in</generator><description><![CDATA[The New Poetry of Philosophy.]]></description><image><url>https://img2.teletype.in/files/13/89/13893215-ebe7-41c1-9504-11dc02ec21db.png</url><title>Титов Климентий</title><link>https://teletype.in/@titoffklim</link></image><link>https://teletype.in/@titoffklim?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/titoffklim?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/titoffklim?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Wed, 29 Apr 2026 21:02:22 GMT</pubDate><lastBuildDate>Wed, 29 Apr 2026 21:02:22 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@titoffklim/rust-fullstack-01</guid><link>https://teletype.in/@titoffklim/rust-fullstack-01?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim</link><comments>https://teletype.in/@titoffklim/rust-fullstack-01?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim#comments</comments><dc:creator>titoffklim</dc:creator><title>Rust Fullstack: Rocket, SeaORM, Dioxus</title><pubDate>Fri, 24 Nov 2023 21:01:46 GMT</pubDate><category>Код</category><description><![CDATA[Для написания фуллстек-приложений на Rust понадобится недюжиное понимание того, как устроены библиотеки и как правильно на них писать. Но есть и плюс: я уже для вас разобрался.]]></description><content:encoded><![CDATA[
  <p id="IwBy">Для написания фуллстек-приложений на Rust понадобится недюжиное понимание того, как устроены библиотеки и фреймворки и как <em>удобно</em> их использовать. Но есть и плюс: я уже для вас разобрался.</p>
  <p id="mmV5">Полный список используемых крейтов для фронтенда и бэкенда - в конце статьи.</p>
  <p id="1dho">В листингах кода полно комментариев.</p>
  <h2 id="Ijje">Структура репозитория</h2>
  <p id="yqEw">Начать следует с создания <code>Cargo.toml</code> в корне репозитория:</p>
  <pre id="LvMA" data-lang="toml">[workspace]
members = [
    &quot;./frontend&quot;,
    &quot;./backend&quot;,
    &quot;./backend/migration&quot;,
    &quot;./data_types&quot;
]
resolver = &quot;2&quot;

[profile.dev]
incremental = true

[profile.release]
opt-level = 3
lto = true
panic = &#x27;abort&#x27;</pre>
  <p id="mecU">Как видно, Cargo позволяет объединить несколько подпроектов в один через рабочие пространства. Помимо бэкенда и фронтенда, виден также подпроект миграций SQL и подпроект типов данных.</p>
  <p id="qgK6">Строка <code>resolver = &quot;2&quot;</code> нужна для корректного управления подпроектами.</p>
  <p id="0WPR">Настройки профилей можете оставить без изменений, можете дописать под себя. Для разработки включена инкрементальная сборка, для выкатки в релиз - LTO-оптимизация.</p>
  <h2 id="4H5f">Миграции SQL</h2>
  <p id="7XCM">В проекте используется SeaORM. Грубо говоря, это - способ управления сущностями через базу данных. Поэтому, чтобы начать разработку, нужно сперва определить типы данных, которые понадобятся для проекта.</p>
  <p id="O1Tt">Для этого в папке <code>backend</code> выполните следующие команды:</p>
  <pre id="XS1Z" data-lang="bash">cargo install sea-orm-cli # устанавливает клиент управления миграциями

sea-orm-cli migrate init # инициализирует подпроект миграций</pre>
  <p id="sAda">Миграции - это обновление структуры базы данных с целью её расширения без потерь информации в автоматическом режиме. Всё, что нужно, - это написать код.</p>
  <p id="7R4p">Типичный файл миграции выглядит так:</p>
  <pre id="S0eP" data-lang="rust">use sea_orm_migration::prelude::*;

#[derive(DeriveMigrationName)]
pub struct Migration;

#[async_trait::async_trait]
impl MigrationTrait for Migration {

  /// Эта функция выполняется при запуске миграции. Если база данных пуста,
  /// и это первая миграция, - то в ней нужно создать таблицы для хранения
  /// информации.
  async fn up(&amp;self, manager: &amp;SchemaManager) -&gt; Result&lt;(), DbErr&gt; {
    manager
      .create_table(
        Table::create()
          .table(Users::Table)
          .if_not_exists()
          .col(ColumnDef::new(Users::Id)
            .big_integer().not_null().auto_increment()
            .primary_key().unique_key()
          )
          .col(ColumnDef::new(Users::Login)
            .string().not_null().unique_key()
          )
          .col(ColumnDef::new(Users::Salt).string().not_null())
          .col(ColumnDef::new(Users::PHash).string().not_null())
          .col(ColumnDef::new(Users::Settings).string().not_null())
          .to_owned()
      ).await
  }

  /// Эта функция используется, чтобы откатить нежелательные изменения при
  /// необходимости. Грубо говоря, здесь нужно писать код, который вернёт
  /// всё, как раньше. Но не прям в 2007.
  async fn down(&amp;self, manager: &amp;SchemaManager) -&gt; Result&lt;(), DbErr&gt; {
    manager.drop_table(Table::drop().table(Users::Table).to_owned()).await
  }
}

/// В перечислении мы определяем поля идентификаторов.
#[derive(Iden)]
enum Users {
  Table, // Да, среди полей таблицы затесалась сама таблица.
         // Подробнее: https://docs.rs/sea-query#iden
  Id,
  Login,
  Salt,
  PHash,
  Settings,
}</pre>
  <p id="Al87">Миграции перечисляются в <code>backend/migrations/lib.rs</code>:</p>
  <pre id="8hZJ" data-lang="rust">pub use sea_orm_migration::prelude::*;

mod m20231007_000001_create_tables; // Указываем файл с миграцией

pub struct Migrator;

#[async_trait::async_trait]
impl MigratorTrait for Migrator {
  fn migrations() -&gt; Vec&lt;Box&lt;dyn MigrationTrait&gt;&gt; {
    vec![
    
      // И добавляем миграции сюда.
      Box::new(m20231007_000001_create_tables::Migration),
      
    ]
  }
}</pre>
  <p id="JnGI">Для запуска миграций вам необходимо создать пустую базу данных и из папки <code>backend</code> выполнить команду:</p>
  <pre id="d8MD" data-lang="bash">sea-orm-cli migrate -u postgres://login:pass@localhost/dbname</pre>
  <p id="CEOB">Затем, чтобы сгенерировать сущности, которые вы сможете использовать в коде на бэкенде, необходимо выполнить следующую команду:</p>
  <pre id="KWyK" data-lang="bash">sea-orm-cli generate entity -o ./src/entities</pre>
  <p id="8KeM">Вуаля, вы можете теперь подключить сущности через <code>mod entities;</code> в <code>main.rs</code> и использовать их примерно следующим образом:</p>
  <pre id="JzEc" data-lang="rust">let new_user = users::ActiveModel {
  login: ActiveValue::Set(data.login.clone()),
  salt: ActiveValue::Set(salt.clone()),
  p_hash: ActiveValue::Set(base64.encode(p_hash)),
  settings: ActiveValue::Set(serde_json::to_string(&amp;settings)?),
  ..Default::default()
};
Users::insert(new_user).exec(db as &amp;DbPool).await?;</pre>
  <h2 id="CjLQ">Общие структуры данных</h2>
  <p id="YGCu">Чтобы использовать все преимущества строгой типизации в Rust, необходимо задать общие типы данных, которые планируется использовать на бэкенде и фронтенде.</p>
  <p id="ODH1">Файл <code>data_types/src/lib.rs</code>:</p>
  <pre id="J64i" data-lang="rust">use chrono::{DateTime, Utc, serde::ts_seconds};
use serde::{Serialize, Deserialize};

// Авторизация и управление аккаунтами:
#[derive(Deserialize, Serialize)]
pub struct SignUpRequestData {
  pub login: String,
  pub name: String,
  pub password: String,
}

#[derive(Deserialize, Serialize)]
pub struct SignInRequestData {
  pub login: String,
  pub password: String,
}

#[derive(Serialize, Deserialize)]
pub struct IsUserValid {
  pub valid: bool,
}

#[derive(Deserialize, Serialize)]
pub struct UserToken {
  pub user_id: i64,
  pub token_str: String,
  #[serde(with = &quot;ts_seconds&quot;)]
  pub birth: DateTime&lt;Utc&gt;,
}</pre>
  <p id="Z9RV">Чтобы использовать подпроект в бэкенде и фронтенде, укажите <code>data_types</code> как зависимость в их <code>Cargo.toml</code>:</p>
  <pre id="NnTG" data-lang="toml">data_types = { path = &quot;../data_types&quot; }</pre>
  <h2 id="1Zvv">Структура бэкенда</h2>
  <h3 id="PpUE">Часть 1. Управление ошибками</h3>
  <p id="Vyh8">Можно было бы использовать <code>anyhow::Error</code> или подобные крейты, но самописные решения предоставляют определённую гибкость:</p>
  <pre id="PXJm" data-lang="rust">use base64::DecodeError;
use bb8_redis::redis::RedisError;
use bb8_redis::bb8::RunError;
use sea_orm::DbErr;
use rocket::{
  request::Request,
  response::{self, Response, Responder},
  http::{ContentType, Status},
};
use std::{io, fmt, num::ParseIntError, string::FromUtf8Error};
use serde::{Serialize, Deserialize};
use serde_json::Error as JsonError;

/// Структура данных ошибок.
#[derive(Serialize, Deserialize, Debug)]
pub struct ErrorResponder {
  message: String,
}

/// Мы воплощаем трейт Responder, чтобы указать,
/// как Rocket будет эту ошибку возвращать клиенту.
#[rocket::async_trait]
impl&lt;&#x27;r&gt; Responder&lt;&#x27;r, &#x27;static&gt; for ErrorResponder {
  fn respond_to(self, _: &amp;&#x27;r Request&lt;&#x27;_&gt;) -&gt; response::Result&lt;&#x27;static&gt; {
    let json_answer = serde_json::to_string(&amp;self).unwrap();
    Response::build()
      .status(Status::Unauthorized)
      .header(ContentType::JSON)
      .sized_body(json_answer.len(), io::Cursor::new(json_answer))
      .ok()
  }
}

impl fmt::Display for ErrorResponder {
  fn fmt(&amp;self, f: &amp;mut fmt::Formatter) -&gt; fmt::Result {
    write!(f, &quot;{}&quot;, self.message)
  }
}

impl From&lt;DbErr&gt; for ErrorResponder {
  fn from(err: DbErr) -&gt; ErrorResponder {
    ErrorResponder { message: err.to_string() }
  }
}

impl From&lt;String&gt; for ErrorResponder {
  fn from(string: String) -&gt; ErrorResponder {
    ErrorResponder { message: string }
  }
}

impl From&lt;&amp;str&gt; for ErrorResponder {
  fn from(str: &amp;str) -&gt; ErrorResponder {
    str.to_owned().into()
  }
}

impl From&lt;io::Error&gt; for ErrorResponder {
  fn from(err: io::Error) -&gt; ErrorResponder {
    err.to_string().into()
  }
}

impl From&lt;JsonError&gt; for ErrorResponder {
  fn from(err: JsonError) -&gt; ErrorResponder {
    err.to_string().into()
  }
}

impl From&lt;ParseIntError&gt; for ErrorResponder {
  fn from(err: ParseIntError) -&gt; ErrorResponder {
    err.to_string().into()
  }
}

impl From&lt;RedisError&gt; for ErrorResponder {
  fn from(err: RedisError) -&gt; ErrorResponder {
    err.to_string().into()
  }
}

impl From&lt;RunError&lt;RedisError&gt;&gt; for ErrorResponder {
  fn from(err: RunError&lt;RedisError&gt;) -&gt; ErrorResponder {
    err.to_string().into()
  }
}

impl From&lt;DecodeError&gt; for ErrorResponder {
  fn from(err: DecodeError) -&gt; ErrorResponder {
    err.to_string().into()
  }
}

impl From&lt;FromUtf8Error&gt; for ErrorResponder {
  fn from(value: FromUtf8Error) -&gt; Self {
    value.to_string().into()
  }
}

/// Делаем биндинг для удобного использования в функциях.
pub type MResult&lt;T&gt; = Result&lt;T, ErrorResponder&gt;;</pre>
  <p id="1bKY">Использование <code>MResult&lt;T&gt;</code> облегчает нашу жизнь таким образом:</p>
  <pre id="2lI4" data-lang="rust">pub async fn login(...) -&gt; MResult&lt;Json&lt;UserToken&gt;&gt; {
  let user_data = find_by_login(&amp;data.login, db).await?;
  let phash_db = base64.decode(user_data.p_hash.as_bytes())?;
  let salted_password = data.password.clone() + &amp;user_data.salt;
  validate_hashes(salted_password.as_bytes(), &amp;phash_db)?;
  let utl_name = get_user_tokens_list_name(&amp;user_data.id);
  let cacher = cacher as &amp;RedisPool;
  let mut cacher_conn = cacher.get().await?;
  let user_tokens_list_len: isize = cacher_conn.llen(&amp;utl_name).await?;
  let token = generate_token(user_data.id)?;
  if user_tokens_list_len &gt;= MAX_TOKENS_PER_USER {
    cacher_conn.ltrim(&amp;utl_name, 0, MAX_TOKENS_PER_USER - 1).await?;
  }
  cacher_conn.lpush(&amp;utl_name, &amp;serde_json::to_string(&amp;token)?).await?;
  Ok(Json(token))
}</pre>
  <h3 id="eIxN">Часть 2. Управление shared-объектами</h3>
  <p id="e3Zh">Для начала загрузим в приложение всю необходимую информацию для его работы и инициализируем объекты для управления данными:</p>
  <pre id="7bGd" data-lang="rust">use bb8_redis::{bb8::Pool as Bb8Pool, RedisConnectionManager};
use dotenv::dotenv;
use sea_orm::*;

pub type RedisPool = Pool&lt;RedisConnectionManager&gt;;
pub type DbPool = DatabaseConnection;

pub struct AppState {
  pub db_url: String,
  pub redis_url: String,
}

pub(super) async fn load_app_state() -&gt; MResult&lt;(AppState, DbPool, RedisPool)&gt; {
  dotenv().ok(); // Загружаем все переменные из файла &#x60;.env&#x60; в окружение
  let state = AppState {
    db_url: std::env::var(&quot;DATABASE_URL&quot;).expect(&quot;DATABASE_URL variable must be set&quot;),
    redis_url: std::env::var(&quot;REDIS_URL&quot;).expect(&quot;REDIS_URL variable must be set&quot;),
  };
  let db = connect_db(&amp;state.db_url).await?;
  let cacher = connect_redis(&amp;state.redis_url).await?;
  Ok((state, db, cacher))
}

async fn connect_db(db_url: &amp;str) -&gt; MResult&lt;DbPool&gt; {
  Ok(Database::connect(db_url).await?)
}

async fn connect_redis(redis_url: &amp;str) -&gt; MResult&lt;RedisPool&gt; {
  let manager = RedisConnectionManager::new(redis_url)?;
  Ok(Bb8Pool::builder().build(manager).await?)
}</pre>
  <p id="7V6G">А теперь напишем функцию, которая полностью заменяет <code>fn main()</code>:</p>
  <pre id="hAXd" data-lang="rust">#[launch]
async fn rocket() -&gt; _ {
  // 1. Установка уровня логгирования.
  if cfg!(debug_assertions) {
    simple_logger::init_with_level(log::Level::Info).unwrap();
  } else {
    simple_logger::init_with_level(log::Level::Warn).unwrap();
  }

  // 2. Загрузка основных параметров и установка соединений с базами данных.
  let (state, db, cacher) = match load_app_state().await {
    Ok((state, db, cacher)) =&gt; (state, db, cacher),
    Err(err) =&gt; panic!(&quot;{}&quot;, err),
  };

  // 3. Запуск сервера.
  rocket::build()
    // перечисляем управляемые объекты:
    .manage(state)
    .manage(db)
    .manage(cacher)
    // перечисляем роуты
    .mount(&quot;/&quot;, routes![
      ...
    ])
}</pre>
  <h3 id="wtnE">Часть 3. Роуты</h3>
  <p id="1LV9">В перечислении параметров функций-роутов можно использовать только те управляемые объекты, которые вам нужны.</p>
  <pre id="Rnf2" data-lang="rust">pub use rocket::{State, serde::json::Json};
pub use rocket::post;

/// Создаём метод POST для пути &#x27;/login&#x27;,
/// который принимает &#x60;application/json&#x60; в теле запроса.
#[post(&quot;/login&quot;, format = &quot;json&quot;, data = &quot;&lt;data&gt;&quot;)]
pub async fn login(
  data: Json&lt;SignInRequestData&gt;, // JSON из тела запроса
  db: &amp;State&lt;DbPool&gt;,
  cacher: &amp;State&lt;RedisPool&gt;,
) -&gt; MResult&lt;Json&lt;UserToken&gt;&gt; {
  ...
  Ok(Json(token))
}</pre>
  <p id="Tf0s">Чтобы запрашивать через параметры роута ещё и ключ аутентификации, используйте следующий код:</p>
  <pre id="Q7xr" data-lang="rust">/// Ключ API через заголовок аутентификации.
pub struct ApiToken(String);

#[rocket::async_trait]
impl&lt;&#x27;r&gt; FromRequest&lt;&#x27;r&gt; for ApiToken {
  type Error = ErrorResponder;

  async fn from_request(req: &amp;&#x27;r Request&lt;&#x27;_&gt;) -&gt; Outcome&lt;Self, Self::Error&gt; {
    /// Извлекаем токен из строки авторизации.
    fn extract_token(key: &amp;str) -&gt; String {
      key.to_owned().replace(&quot;Bearer &quot;, &quot;&quot;)
    }

    // Получаем текст заголовка &#x60;Authorization&#x60;:
    match req.headers().get_one(&quot;Authorization&quot;) {
      None =&gt; Outcome::Error((Status::Forbidden, &quot;Authorization token is missing.&quot;.into())),
      Some(key) =&gt; Outcome::Success(ApiToken(extract_token(key))),
    }
  }
}</pre>
  <p id="BxCS">Тогда роуты принимают подобный вид:</p>
  <pre id="VUNU" data-lang="rust">#[get(&quot;/project/&lt;project_id&gt;&quot;)]
pub async fn get_project_info(
  project_id: i64, // Запрос &#x60;/project/2221&#x60; установит
                   // в переменную &#x60;project_id&#x60; значение 2221.
  db: &amp;State&lt;DbPool&gt;,
  cacher: &amp;State&lt;RedisPool&gt;,
  token: ApiToken, // Токен, который клиент должен передавать
                   // вместе с запросом.
) -&gt; MResult&lt;Json&lt;ProjectCardInfo&gt;&gt; { ... }</pre>
  <h3 id="JP3n">Запуск</h3>
  <pre id="02VQ" data-lang="bash">cd backend
cargo run --release</pre>
  <h2 id="Xxih">Структура фронтенда</h2>
  <h3 id="DfFj">Часть 1. Конфигурация приложения</h3>
  <p id="KP5y">Создайте <code>Dioxus.toml</code> с подобным содержимым:</p>
  <pre id="KfjE" data-lang="toml">[application]
name = &quot;app_name&quot;
default_platform = &quot;web&quot;
out_dir = &quot;../dist&quot;
asset_dir = &quot;public&quot;

[web.app]
title = &quot;App Title&quot;

[web.watcher]
watch_path = [&quot;src&quot;, &quot;public&quot;]

[web.resource]
# Если требуется использовать TailwindCSS,
# изучите https://dioxuslabs.com/learn/0.4/cookbook/tailwind
style = [&quot;tailwind.css&quot;]
script = []

[web.resource.dev]
style = []
script = []</pre>
  <p id="B8yl">И установите <code>dioxus-cli</code>:</p>
  <pre id="Fids" data-lang="bash">cargo install dioxus-cli</pre>
  <h3 id="O467">Часть 2. Облегчаем себе жизнь при работе с LocalStorage</h3>
  <p id="wRx7">Используем простейшие функции для получения и записи значений:</p>
  <pre id="cyle" data-lang="rust">pub type MResult = Result&lt;(), AppError&gt;;
pub static APP_TOKEN_LOCALSTORAGE_KEY: &amp;str = &quot;token&quot;;

/// Чтение из локального хранилища.
pub fn get_from_storage(key: &amp;str) -&gt; Result&lt;String, AppError&gt; {
  let window = match web_sys::window() {
    None =&gt; return Err(&quot;Не удалось получить параметры окна&quot;.into()),
    Some(window) =&gt; window,
  };
  let storage = match window.local_storage() {
    Err(_) =&gt; return Err(&quot;Не удалось получить доступ к LocalStorage&quot;.into()),
    Ok(None) =&gt; return Err(&quot;LocalStorage пуст&quot;.into()),
    Ok(Some(storage)) =&gt; storage,
  };
  if let Ok(Some(value)) = storage.get_item(key) {
    Ok(value)
  } else {
    Err(format!(&quot;Не удалось получить значение по ключу \&quot;{}\&quot;&quot;, key).into())
  }
}

/// Запись в локальное хранилище.
pub fn put_in_storage(key: &amp;str, val: &amp;str) -&gt; MResult {
  let window = match web_sys::window() {
    None =&gt; return Err(&quot;Не удалось получить параметры окна&quot;.into()),
    Some(window) =&gt; window,
  };
  let storage = match window.local_storage() {
    Err(_) =&gt; return Err(&quot;Не удалось получить доступ к LocalStorage&quot;.into()),
    Ok(None) =&gt; return Err(&quot;LocalStorage пуст&quot;.into()),
    Ok(Some(storage)) =&gt; storage,
  };
  if storage.set_item(key, val).is_err() {
    return Err(&quot;Не удалось сохранить значение в LocalStorage&quot;.into())
  }
  Ok(())
}

/// Получение заголовка авторизации.
pub fn get_authorization_token() -&gt; Result&lt;String, AppError&gt; {
  get_from_storage(APP_TOKEN_LOCALSTORAGE_KEY)
}</pre>
  <h3 id="gKQl">Часть 3. Добавляем функции для запросов к серверу</h3>
  <pre id="v8mV" data-lang="rust">pub static BASE_API_URL: &amp;str = &quot;schema://example.com/&quot;;
pub static LOGIN_API: &amp;str = &quot;login&quot;;
pub static AUTH_API: &amp;str = &quot;user&quot;;
pub static CHECK_USER_API: &amp;str = &quot;/check&quot;;

/// Осуществляет вход в аккаунт.
pub async fn login(username: String, password: String) -&gt; MResult {
  let token: UserToken = reqwest::Client::new()
    .post(format!(&quot;{}{}&quot;, BASE_API_URL, LOGIN_API))
    .json(&amp;SignInRequestData { login: username, password })
    .send()
    .await?
    .json::&lt;UserToken&gt;()
    .await?;
  put_in_storage(APP_TOKEN_LOCALSTORAGE_KEY, &amp;serde_json::to_string(&amp;token).unwrap())
}

/// Осуществляет проверку пользовательского токена.
pub async fn check_user_token() -&gt; MResult {
  let res: IsUserValid = reqwest::Client::new()
    .post(format!(&quot;{}{}{}&quot;, BASE_API_URL, AUTH_API, CHECK_USER_API))
    .bearer_auth(get_authorization_token()?)
    .send()
    .await?
    .json()
    .await?;
  if !res.valid { return Err(&quot;Пользователь не авторизован&quot;.into()) }
  Ok(())
}</pre>
  <h3 id="xxic">Часть 4. Подготовка реактивных состояний приложения</h3>
  <p id="tpj2">Чтобы Dioxus был способен динамически отрисовывать веб-страницу в зависимости от изменения данных, их необходимо задать заранее:</p>
  <pre id="Ig4c" data-lang="rust">/// Структура данных, которая отвечает за отображение необходимого раздела.
#[derive(Clone, Debug, PartialEq)]
pub enum InAppLocation {
  Unset,
  Auth,
  Register,
  Projects,
  ProjectSurvey(ProjectID),
  PrepareRecommendationsByTest(ProjectID),
  // ...
}

/// Вспомогательная структура для принудительной отрисовки DOM.
#[derive(Clone, Debug, PartialEq)]
pub enum LocalUpdate {
  NotScheduled,
  Scheduled,
}</pre>
  <p id="veKF">Далее мы создаём структуру данных, которую будем передавать во все компоненты приложения по необходимости:</p>
  <pre id="B5ia" data-lang="rust">#[derive(Copy, Clone)]
pub struct AppHooks&lt;&#x27;a&gt; {
  pub app_location: &amp;&#x27;a UseState&lt;InAppLocation&gt;,
  pub update_scheduler: &amp;&#x27;a UseState&lt;LocalUpdate&gt;,
  pub project_selected: &amp;&#x27;a UseState&lt;ProjectID&gt;,
  pub get_summaries_fut: &amp;&#x27;a UseFuture&lt;Result&lt;Vec&lt;ProjectLineSummary&gt;, AppError&gt;&gt;,
  pub get_project_card_fut: &amp;&#x27;a UseFuture&lt;Result&lt;ProjectCardInfo, AppError&gt;&gt;,
  pub get_project_card_st: &amp;&#x27;a UseState&lt;ProjectID&gt;,
  // ...
}

impl&lt;&#x27;a&gt; AppHooks&lt;&#x27;a&gt; {
  pub fn new(cx: Scope&lt;&#x27;a&gt;) -&gt; Self {
    // Состояния приложения.
    let app_location = use_state(cx, || InAppLocation::Unset);
    let update_scheduler = use_state(cx, || LocalUpdate::NotScheduled);

    // Задание опционального хука
    let project_selected = use_state(cx, || 0);
    let get_project_card_fut = use_future(cx, (), |_| {
      let project_id = project_selected.to_owned();

      async move { get_project_info(*project_id).await }
    });

    // Задание опционального хука
    // Мы хотим, чтобы замыкание-футура выполнялась только тогда,
    // когда &#x60;get_project_survey_st&#x60; установлен в &#x60;true&#x60;.
    let get_project_survey_st = use_state(cx, || false);
    let get_project_survey_fut = use_future(cx, (), |_| {
      let survey_loaded = get_project_survey_st.to_owned();

      async move {
        if survey_loaded == true {
          let res = get_project_survey().await;
          if res.is_ok() { survey_loaded.set(true); }
          res
        } else { Err(&quot;Ожидание запроса.&quot;.into()) }
      }
    });

    // Отдаём хуки
    AppHooks {
      // Состояния
      app_location,
      update_scheduler,
      project_selected,
      // Исполняемые замыкания
      get_summaries_fut: use_future(cx, (), |_| async move { get_summaries().await }),
      get_project_card_fut,
      get_project_card_st: use_state(cx, || 0),
      // ...
    }
  }
}</pre>
  <h3 id="83Go">Часть 5. Подготавливаем главный компонент приложения и запуск</h3>
  <p id="R12P">Главный компонент приложения играет роль роутера, раскидывая пользователя по компонентам в зависимости от состояния приложения <code>AppLocation</code>.</p>
  <pre id="ghJX" data-lang="rust">fn main() { dioxus_web::launch(App); }</pre>
  <pre id="u2oV" data-lang="rust">use dioxus::core::{Element, Scope};
use dioxus::prelude::*;

/// Главный компонент веб-приложения.
fn App(cx: Scope) -&gt; Element {
  // Создание хранилища состояний
  let hx = AppHooks::new(cx);

  // Замыкание для проверки аутентификации
  let apploc_fut = use_future(cx, (), |_| async move { check_user_token().await });

  // Раскладка для отображения состояния загрузки
  let loading_lt = rsx!( div { &quot;Загрузка...&quot; });

  // Отрисовка приложения
  // Поскольку отрисовка условная, все состояния и хуки должны 
  // выноситься в безусловный блок. Следовательно, данные до компонентов
  // должны прокидываться из главного компонента.
  cx.render({

    // 1. Получение текущего местоположения
    let curr_location = (**hx.app_location).clone();

    // 2. Отрисовка страницы в соответствии с местоположением
    match curr_location {

      // Если положение не установлено -
      // сравниваем с результатом валидации токена.
      InAppLocation::Unset =&gt; {
        match apploc_fut.value() {
          Some(Ok(_)) =&gt; { hx.app_location.set(InAppLocation::Projects); },
          Some(Err(_)) =&gt; { hx.app_location.set(InAppLocation::Auth); },
          None =&gt; {},
        };
        loading_lt
      },

      // Страницы:
      InAppLocation::Auth =&gt; rsx!(Auth(cx, hx)),
      InAppLocation::Register =&gt; rsx!(Register(cx, hx.app_location)),
      InAppLocation::Projects =&gt; rsx!(Projects(cx, hx)),
      InAppLocation::ProjectSurvey(project_id) =&gt; rsx!(ProjectSurvey(cx, hx, project_id)),
      // ...
    }
  })
}</pre>
  <p id="aLmI">Немного пояснений:</p>
  <ol id="BFr5">
    <li id="Iynq">После установки значений или обновления состояния замыканий-футур будет выполнен рендеринг VirtualDOM, и изменения будут при необходимости отрисованы.</li>
    <li id="rFiO">Внутри блока <code>cx.render({ ... })</code> необходимо писать код, который должен будет выполняться каждую перерисовку, а перед ним - код, который должен будет выполниться лишь один раз.</li>
    <li id="6Cwm">При этом нельзя в компонентах использовать любые хуки (функции Dioxus, которые начинаются на <code>use_</code>), если эти компоненты будут отрисованы условно (см. <strong>правила хуков</strong> по ссылке ниже). Например, <code>InAppLocation::Projects</code> будет отрисован только после того, как отрисуется <code>Auth</code>, и будет выполнена авторизация. Это - причина, почему хуки лучше выносить в отдельную структуру данных - <code>AppHooks</code>.</li>
  </ol>
  <p id="Nc4n">Дополнительная информация про <a href="https://dioxuslabs.com/learn/0.4/guide/state" target="_blank">стейты</a>, <a href="https://dioxuslabs.com/learn/0.4/guide/state#the-rules-of-hooks" target="_blank">правила хуков</a>, <a href="https://dioxuslabs.com/learn/0.4/reference/use_future" target="_blank">футуры</a>, <a href="https://dioxuslabs.com/learn/0.4/reference/dynamic_rendering" target="_blank">динамический рендеринг</a> и <a href="https://dioxuslabs.com/learn/0.4/reference/spawn" target="_blank">футуры, которые будут выполняться по какому-то событию</a>.</p>
  <h3 id="Wsa2">Часть 6. Компоненты</h3>
  <p id="iiCn">Код компонента страницы авторизации выглядит приблизительно так:</p>
  <pre id="Jb32" data-lang="rust">use dioxus::prelude::*;
use dioxus_html::input_data::keyboard_types::Code as KeyCode;
use log::{error, debug};

use crate::requests::auth::login;
use crate::states::{AppHooks, InAppLocation, LocalUpdate};

/// Страница авторизации пользователя.
pub fn Auth&lt;&#x27;a&gt;(cx: Scope&lt;&#x27;a&gt;, hx: AppHooks&lt;&#x27;a&gt;) -&gt; Element&lt;&#x27;a&gt; {
  // Создаём хуки, которые будут использоваться только в этом компоненте
  let email = use_state(cx, || &quot;&quot;.to_string());
  let password = use_state(cx, || &quot;&quot;.to_string());
  
  // Вход в аккаунт
  // Это замыкание будет выполнено по нажатию на кнопку &quot;Войти&quot;
  let auth_fut = move |_| {
    cx.spawn({
      to_owned![email, password];
      let app_location = hx.app_location.to_owned();
      let update_scheduler = hx.update_scheduler.to_owned();
      async move {
        match login(
          email.current().to_string().clone(),
          password.current().to_string().clone()
        ).await {
          Ok(_) =&gt; {
            debug!(&quot;Токен получен.&quot;);
            app_location.set(InAppLocation::Projects);
            update_scheduler.set(LocalUpdate::Scheduled);
          },
          Err(e) =&gt; error!(&quot;{}&quot;, e),
        }
      }
    });
  };
  
  // Вход в аккаунт
  // Это замыкание будет выполено по нажатию на кнопку &#x60;Enter&#x60; на поле пароля
  //
  // Q: Почему нужно два одинаковых внешне замыкания?
  // A: Из-за различия в типах событий по нажатию кнопки мыши или клавиатуры.
  let auth_by_enter_fut = move |_| {
    cx.spawn({
      to_owned![email, password];
      let app_location = hx.app_location.to_owned();
      let update_scheduler = hx.update_scheduler.to_owned();
      async move {
        match login(
          email.current().to_string().clone(),
          password.current().to_string().clone()
        ).await {
          Ok(_) =&gt; {
            debug!(&quot;Токен получен.&quot;);
            app_location.set(InAppLocation::Projects);
            update_scheduler.set(LocalUpdate::Scheduled);
          },
          Err(e) =&gt; error!(&quot;{}&quot;, e),
        }
      }
    });
  };
  
  // Отрисовка страницы
  cx.render(rsx! {
    div {
      class: &quot;flex mx-auto justify-center items-center h-screen w-2/5&quot;,
      div {
        p {
          class: &quot;text-center font-medium mb-2&quot;,
          &quot;Авторизация&quot;,
        },
        input {
          class: &quot;border-b-2 w-full hover:outline-2 outline-offset-2 mb-1 rounded-sm&quot;,
          placeholder: &quot;Электронная почта&quot;,
          r#type: &quot;email&quot;, // Так мы можем использовать зарезервированные
                           // в языке Rust слова, которые используются в HTML.
          value: &quot;{email}&quot;, // Значение будет соответствовать значению хука &#x60;email&#x60;.
          oninput: move |evt| email.set(evt.value.clone()),
        },
        input {
          class: &quot;border-b-2 w-full hover:outline-2 outline-offset-2 mb-1 rounded-sm&quot;,
          r#type: &quot;password&quot;,
          placeholder: &quot;Пароль&quot;,
          value: &quot;{password}&quot;,
          oninput: move |evt| password.set(evt.value.clone()),
          onkeypress: move |evt| {
            if evt.code() == KeyCode::Enter { auth_by_enter_fut(evt); }
          }
        },
        div {
          class: &quot;flex flex-row columns-2 block gap-4&quot;,
          button {
            class: &quot;w-full rounded-xl shadow-md px-4 py-1 text-white bg-orange-500&quot;,
            onclick: auth_fut,
            &quot;Войти&quot;
          },
          button {
            class: &quot;w-full rounded-xl shadow-md px-4 py-1 text-white bg-teal-800&quot;,
            onclick: move |_| { hx.app_location.set(InAppLocation::Register); },
            &quot;Зарегистрироваться&quot;
          },
        },
      }
    }
  })
}</pre>
  <p id="UlEJ">Код компонента страницы проектов:</p>
  <pre id="s0WR" data-lang="rust">pub fn Projects&lt;&#x27;a&gt;(cx: Scope&lt;&#x27;a&gt;, hx: AppHooks&lt;&#x27;a&gt;) -&gt; Element&lt;&#x27;a&gt; {
  // Создание проекта
  let new_project_fut = move |_| {
    cx.spawn({
      let update_scheduler = hx.update_scheduler.clone();
      async move {
        match new_project().await {
          Ok(_) =&gt; {
            debug!(&quot;Проект создан.&quot;);
            update_scheduler.set(LocalUpdate::Scheduled);
          },
          Err(e) =&gt; error!(&quot;{}&quot;, e),
        }
      }
    });
  };

  // Отрисовка страницы
  cx.render({

    // 1. Проверка планировщика (если добавили/удалили проект)
    let curr_summaries_scheduler_state = hx.update_scheduler.clone();

    if curr_summaries_scheduler_state == LocalUpdate::Scheduled {
      hx.update_scheduler.set(LocalUpdate::NotScheduled);
      hx.get_summaries_fut.restart(); // так можно перезапускать футуры
                                      // и ожидать от них новых значений
    }

    // 2. Обновление значений из корутины
    let mut summaries_list = Vec::new();
    if hx.get_summaries_fut.value().is_some() {
      let res = hx.get_summaries_fut.value().unwrap();
      if res.is_ok() {
        let summaries_vec = res.as_ref().unwrap();
        for summary in summaries_vec {
          summaries_list.push(rsx!(ProjectLine(cx, summary.clone(), hx.update_scheduler, hx.project_selected)))
        }
      }
    }

    // 3. Отрисовка превью проекта
    let project_card = match **hx.project_selected {
      0 =&gt; None,
      _ =&gt; Some(rsx!(ProjectCard(cx, hx))),
    };

    // 4. Финальная отрисовка
    rsx!{
      SideBar {
        app_location: hx.app_location.clone()
      },
      div {
        class: &quot;sm:pl-80 md:pl-80 lg:pl-80 pl-12 pr-12 pt-8 pb-8&quot;,
        p {
          class: &quot;font-medium text-xl select-none pb-4&quot;,
          &quot;Мои проекты&quot;
        },
        summaries_list.into_iter(), // будет последовательно отрисован
                                    // список компонентов
        div {
          class: &quot;pt-4 py-4&quot;,
          button {
            class: &quot;animate-slide_in pl-8 pr-8 shadow-md rounded-full px-4 py-1 text-white bg-[#607a79] hover:bg-[#719190]&quot;,
            onclick: new_project_fut,
            &quot;Начать новый проект&quot;
          }
        },
        project_card, // отметим, что можно передавать Option&lt;LazyNodes&lt;..&gt;&gt;
      }
    }
  })
}</pre>
  <h3 id="xGi0">Сборка</h3>
  <p id="UPyK">Для сборки необходимо выполнить следующую команду:</p>
  <pre id="gqnn" data-lang="bash">dx build --release</pre>
  <h2 id="Ur0p">Встраивание фронта в бэк</h2>
  <p id="crQR">Добавьте следующие функции в <code>backend/main.rs</code>:</p>
  <pre id="ajh4" data-lang="rust">// Файлы для фронтенда.
#[get(&quot;/&quot;)]
async fn frontend() -&gt; Result&lt;NamedFile, NotFound&lt;String&gt;&gt; {
  let path = Path::new(&quot;../dist/index.html&quot;);
  NamedFile::open(&amp;path).await.map_err(|e| NotFound(e.to_string()))
}

// Если используете TailwindCSS
#[get(&quot;/tailwind.css&quot;)]
async fn get_tw_css() -&gt; Result&lt;NamedFile, NotFound&lt;String&gt;&gt; {
  let path = Path::new(&quot;../dist/tailwind.css&quot;);
  NamedFile::open(&amp;path).await.map_err(|e| NotFound(e.to_string()))
}

#[get(&quot;/assets/&lt;path..&gt;&quot;)]
async fn get_dx_app_internals(path: PathBuf) -&gt; Option&lt;NamedFile&gt; {
  NamedFile::open(Path::new(&quot;../dist/assets/&quot;).join(path)).await.ok()
}</pre>
  <p id="MH5C">И измените функцию <code>async fn rocket()</code>:</p>
  <pre id="xv6t" data-lang="rust">rocket::build()
  // перечисляем роуты
  .mount(&quot;/&quot;, routes![
    frontend, get_dx_app_internals, get_tw_css,
    // ...
  ])</pre>
  <h2 id="kUfN">Возможные проблемы</h2>
  <h3 id="1kG3">1. <code>/favicon.ico</code> error</h3>
  <p id="HgYh">Проблема с <code>favicon.ico</code>? Да, бывает. Измените <code>frontend/index.html</code>:</p>
  <pre id="qlwv" data-lang="html">&lt;head&gt;
  &lt;!-- ... --&gt;
  &lt;link rel=&quot;shortcut icon&quot; type=&quot;image/avif&quot; href=&quot;favicon.avif&quot;&gt;
  &lt;!-- ... --&gt;
&lt;/head&gt;</pre>
  <p id="g9CI">Сконвертируйте иконку в AVIF и добавьте ещё один роут в <code>backend</code>:</p>
  <pre id="YKX0" data-lang="rust">#[get(&quot;/favicon.avif&quot;)]
async fn get_favicon() -&gt; Result&lt;NamedFile, NotFound&lt;String&gt;&gt; {
  let path = Path::new(&quot;../dist/favicon.avif&quot;);
  NamedFile::open(&amp;path).await.map_err(|e| NotFound(e.to_string()))
}</pre>
  <h3 id="23XX">2. Разрешение проблем с CORS</h3>
  <p id="Xdpm">Если вы хотите на сервере разрешить CORS, добавьте следующий код:</p>
  <pre id="JttL" data-lang="rust">/// Разрешает CORS.
pub struct CorsAllower;

#[rocket::async_trait]
impl Fairing for CorsAllower {
  fn info(&amp;self) -&gt; Info {
    Info {
      name: &quot;Add CORS headers to responses&quot;,
      kind: Kind::Response
    }
  }

  async fn on_response&lt;&#x27;r&gt;(&amp;self, _request: &amp;&#x27;r Request&lt;&#x27;_&gt;, response: &amp;mut Response&lt;&#x27;r&gt;) {
    response.set_header(Header::new(&quot;Access-Control-Allow-Origin&quot;, &quot;*&quot;));
    response.set_header(Header::new(&quot;Access-Control-Allow-Methods&quot;, &quot;POST, PUT, DELETE, PATCH, GET, OPTIONS&quot;));
    response.set_header(Header::new(&quot;Access-Control-Allow-Headers&quot;, &quot;Authorization, Content-Type&quot;));
    response.set_header(Header::new(&quot;Access-Control-Allow-Credentials&quot;, &quot;true&quot;));
  }
}

/// Разрешает запросы OPTIONS.
#[allow(dead_code)]
#[options(&quot;/&lt;_path..&gt;&quot;)]
pub async fn cors_options_preflight(_path: std::path::PathBuf) -&gt; MResult&lt;()&gt; { Ok(()) }</pre>
  <p id="5LxK">И измените <code>async fn rocket()</code>:</p>
  <pre id="keuU" data-lang="rust">rocket::build()
  .mount(&quot;/&quot;, routes![
    cors_options_preflight, // &lt;- позволяет отвечать на OPTIONS-запросы
    // ..
  ])
  .attach(CorsAllower); // &lt;- добавляет разрешающие заголовки</pre>
  <h2 id="tn4h">Полезные библиотеки</h2>
  <h3 id="Gop6">1. Бэкенд</h3>
  <pre id="sKCP" data-lang="toml">[dependencies]
base64 = &quot;0.21&quot;
bb8-redis = &quot;0.13&quot;
chrono = { version = &quot;0.4&quot;, features = [&quot;serde&quot;] }
data_types = { path = &quot;../data_types&quot; }
dotenv = &quot;0.15.0&quot;
log = &quot;0.4.20&quot;
passwords = &quot;3.1&quot;
rocket = { version = &quot;0.5.0-rc.4&quot;, features = [&quot;tls&quot;, &quot;json&quot;] }
sea-orm = { version = &quot;0.12&quot;, features = [&quot;sqlx-postgres&quot;, &quot;sqlx-sqlite&quot;, &quot;runtime-tokio-native-tls&quot;, &quot;macros&quot;, &quot;mock&quot;] }
sea-orm-migration = &quot;0.12&quot;
serde = { version = &quot;1.0&quot;, features = [&quot;derive&quot;] }
serde_json = &quot;1.0&quot;
sha3 = &quot;0.10&quot;
tokio = { version = &quot;1.33.0&quot;, features = [&quot;sync&quot;] }
uuid = { version = &quot;1.5.0&quot;, features = [&quot;v4&quot;] }</pre>
  <h3 id="2K1P">2. Фронтенд</h3>
  <pre id="Aq2K" data-lang="toml">[dependencies]
async-recursion = &quot;1.0&quot;
chrono = { version = &quot;0.4&quot;, features = [&quot;serde&quot;] }
console_log = &quot;1&quot;
data_types = { path = &quot;../data_types&quot; }
dioxus = &quot;0.4&quot;
dioxus-free-icons = { version = &quot;0.7&quot;, features = [&quot;bootstrap&quot;] }
dioxus-html = &quot;0.4&quot;
dioxus-web = &quot;0.4&quot;
futures = &quot;0.3&quot;
log = &quot;0.4&quot;
reqwest = { version = &quot;0.11&quot;, features = [&quot;json&quot;] }
serde = { version = &quot;1.0&quot;, features = [&quot;derive&quot;] }
serde_json = &quot;1.0&quot;
web-sys = { version = &quot;0.3&quot;, features = [&quot;Storage&quot;, &quot;Window&quot;] }</pre>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@titoffklim/threaded-gtk</guid><link>https://teletype.in/@titoffklim/threaded-gtk?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim</link><comments>https://teletype.in/@titoffklim/threaded-gtk?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim#comments</comments><dc:creator>titoffklim</dc:creator><title>Написание приложений на Python с использованием фреймворка GTK</title><pubDate>Fri, 04 Aug 2023 11:50:12 GMT</pubDate><description><![CDATA[Написание десктопных приложений подразумевает разветвлённую многопоточную систему управления логикой. Причина проста: эвентлуп GTK требует минимальное число операций в функциях по отрисовке интерфейса по причине его подвисания в противном случае. Поэтому подход простой:]]></description><content:encoded><![CDATA[
  <p id="uQPw">Написание десктопных приложений подразумевает разветвлённую многопоточную систему управления логикой. Причина проста: эвентлуп GTK требует минимальное число операций в функциях по отрисовке интерфейса по причине его подвисания в противном случае. Поэтому подход простой:</p>
  <h2 id="1hw5">1. Написание функций по отрисовке интерфейса</h2>
  <p id="OYrj">Для разработки требуется установленная в системе библиотека PyGObject. Её предлагается использовать следующим образом:</p>
  <pre id="EMku">import gi

gi.require_version(&quot;Gdk&quot;, &quot;3.0&quot;)
gi.require_version(&quot;Gtk&quot;, &quot;3.0&quot;)

from gi.repository import Gdk, GLib, Gio, Gtk, GObject</pre>
  <p id="TiMH">Для быстрого прототипирования предлагается отрисовывать формы в Glade и подключать через декоратор:</p>
  <pre id="Iytq">@Gtk.Template.from_file(&quot;main_window.glade&quot;)
class MainWindow(Gtk.ApplicationWindow):
  __gtype_name__ = &quot;main_window&quot;
  # подключение к необходимым объектам в прототипе
  rootcont = Gtk.Template.Child(&quot;rootcont&quot;)

  def __init__(self, **kwargs):
    super().__init__(**kwargs)
    ...</pre>
  <p id="06Yv">Стилевое оформление прописывается в каскадных таблицах:</p>
  <pre id="aQbb">provider = Gtk.CssProvider()
provider.load_from_path(&quot;./style.css&quot;)
screen = Gdk.Screen.get_default()
Gtk.StyleContext.add_provider_for_screen(
  screen, provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
)</pre>
  <p id="SEdf">Использование системы сигналов и слотов на примере с кнопками:</p>
  <pre id="LeiW">self.get_info_btn.connect(&quot;clicked&quot;, self.show_info_screen)</pre>
  <p id="Gj1Q">Документация по PyGObject: <a href="https://lazka.github.io/pgi-docs/Gtk-3.0/index.html" target="_blank">https://lazka.github.io/pgi-docs/Gtk-3.0/index.html</a></p>
  <h2 id="juou">2. Добавление логики в приложение</h2>
  <pre id="TUL5">def threaded_logic():
  # some logic
t = Thread(target=threaded_logic)
t.daemon = True
t.start()</pre>
  <p id="X4NO">Коммуникацию предлагается обеспечивать через сигналы и очереди:</p>
  <pre id="0QSr">class MySignals(GObject.GObject):
  __gsignals__ = {
    &#x27;get&#x27;: (GObject.SignalFlags.RUN_FIRST, None, ()),
    &#x27;pass&#x27;: (GObject.SignalFlags.RUN_FIRST, None, ()),
    &#x27;default_screen&#x27;: (GObject.SignalFlags.RUN_FIRST, None, ()),
    &#x27;show_error&#x27;: (GObject.SignalFlags.RUN_FIRST, None, (str,)),
    &#x27;show_critical&#x27;: (GObject.SignalFlags.RUN_FIRST, None, (str,))
  }

signals = MySignals()
some_objects = queue.Queue()</pre>
  <p id="DTl8">Из потоков напрямую запрещается производить вызов отрисовки интерфейса, равно как и вызывать сигналы (в противном случае - segfault). Предлагается использовать безопасный способ:</p>
  <pre id="Krvx">Gdk.threads_add_idle(
  GLib.PRIORITY_HIGH_IDLE, signals.emit, &#x27;default_screen&#x27;
)
Gdk.threads_add_idle(
  GLib.PRIORITY_HIGH_IDLE, lambda: self.curr_sequencer.prev()
)</pre>
  <h2 id="Rk3k">3. Последовательность запуска</h2>
  <p id="SeMG">Сначала запускаются необходимые фоновые потоки, затем - эвентлуп GTK:</p>
  <pre id="LgCC">class Application(Gtk.Application):
  def __init__(self, *args, **kwargs):
    super().__init__(
      *args,
      application_id=&quot;org.comp.app&quot;,
      flags=Gio.ApplicationFlags.FLAGS_NONE,
      **kwargs,
    )

  def do_activate(self):
    self.win = MainWindow(application=self)
    self.win.present()
    self.win.show_all()


if __name__ == &quot;__main__&quot;:
  Application().run(sys.argv)</pre>
  <p id="bxh8">Вуаля!</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@titoffklim/russian-linux-comparison</guid><link>https://teletype.in/@titoffklim/russian-linux-comparison?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim</link><comments>https://teletype.in/@titoffklim/russian-linux-comparison?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim#comments</comments><dc:creator>titoffklim</dc:creator><title>Сравнение российских ОС (дистрибутивов Linux общего назначения)</title><pubDate>Fri, 04 Aug 2023 11:00:20 GMT</pubDate><description><![CDATA[<img src="https://img4.teletype.in/files/f8/a7/f8a7a003-73a7-42f2-9979-68512d444904.png"></img>Препринт статьи. Авторы: Смирнова П.В., Титов К.А. Оригинальное название: &quot;Управление цифровой трансформацией бизнеса с учетом требований по импортозамещению программного обеспечения&quot;]]></description><content:encoded><![CDATA[
  <p id="h683"><em>Препринт статьи. Авторы: Смирнова П.В., Титов К.А. Оригинальное название: &quot;<strong>Управление цифровой трансформацией бизнеса с учетом требований по импортозамещению программного обеспечения</strong>&quot;</em></p>
  <p id="wzEU">Цифровая трансформация современных предприятий является необходимым ответом на актуальные нормативно-правовые требования и требования современной экономики, ориентированной на использование цифровых решений.</p>
  <p id="h4V2">Важной задачей в этих условиях является реализация общенационального курса на импортозамещение иностранного программного обеспечения. Значительная работа в этой области ведется с 2015 года – с момента создания реестра отечественного программного обеспечения. В это же время на государственном уровне предпринимаются меры по организации перехода предприятий с государственным участием на отечественные программные решения, входящие в Реестр российского программного обеспечения [4]. Требования по переходу отечественного бизнеса на российское ПО закреплены также и в национальной программе «Цифровая экономика» [9].</p>
  <p id="xmQo">В текущей экономической ситуации российское государство активно поддерживает развитие отрасли информационных технологий, подготовку новых специалистов и особое внимание уделяет обеспечению безопасности данных граждан. В 2022 году было принято решение, что до 2025 года всем предприятиям с зарубежными средствами защиты информации необходимо составить план по переходу на отечественные аналоги [12].</p>
  <p id="0Kza">Переход на отечественные программные продукты в первую очередь затронул государственные компании и стратегические производства, особенно в сфере оборонной промышленности. Самым сложным в переходе является замена операционной системы, ведь отечественные разработчики предлагают широкий выбор систем, однако у руководства компаний нет понимания какая операционная система подойдет лучше именно для их производства или бизнеса.</p>
  <p id="fW1V">Цель исследования заключается в разработке критериального метода оценки и выбора операционных систем для предприятий, реализующих процесс импортозамещения программного обеспечения.</p>
  <p id="WOLY">Задачи, обеспечивающие достижение поставленной цели, сформулированы авторами следующим образом:</p>
  <ul id="9abb">
    <li id="75AA">определение подходов к отбору операционных систем, рекомендованных предприятиям для осуществления процессов импортозамещения в области программного обеспечения; </li>
    <li id="M4Pa">выбор и обоснование критериев для сравнения сформированного на предыдущем этапе перечня операционных систем;</li>
    <li id="I3P3">разработка балльных шкал для оценки выбранных операционных систем;</li>
    <li id="PwbI">оценивание выбранных операционных систем по частным критериям и итоговое результирование оценок;</li>
    <li id="7RIr">формализация применения метода оценки и выбора операционной системы, используемой в организации для решения задач цифровой трансформации. </li>
  </ul>
  <p id="RDZi">Концептуальные подходы к выбору критериев осуществлены в ходе предварительного исследования [11], обсуждение результатов исследования показало необходимость расширения перечня операционных систем, формализации критериев и шкал балльных оценок для каждого приведенного параметра, а также уточнения показателя, характеризующего экономическую устойчивость организаций-разработчиков.</p>
  <h2 id="HwXa"><strong>Объекты и методы исследования</strong></h2>
  <p id="v6K3"><strong>Отбор рассматриваемых продуктов.</strong> Выбор ОС для сравнения выполнен на основе данных Реестра российского программного обеспечения (ПО). Были определены следующие требования для отбора операционных систем [11]:</p>
  <ol id="uLMM">
    <li id="P7SQ">Является операционной системой общего назначения (классификатор в Реестре российского программного обеспечения).</li>
    <li id="GpUe">Использует ядро Linux.</li>
    <li id="fA2t">Применяется на автоматизированных рабочих местах;  имеет сертификат соответствия ФСТЭК.</li>
  </ol>
  <p id="z9yH">В результате отбора были выбраны для рассмотрения шесть операционных систем:</p>
  <ol id="1OES">
    <li id="rMFW">ОСнова</li>
    <li id="3fy1">РЕД ОС</li>
    <li id="n8NX">ALT Linux</li>
    <li id="fi3H">Astra Linux</li>
    <li id="sPQK">ICLinux</li>
    <li id="kFdc">ROSA Linux.</li>
  </ol>
  <p id="cOPD">При этом, по состоянию на момент подготовки статьи года сайт ICLinux (<a href="https://iclinux.icl.ru" target="_blank">https://iclinux.icl.ru</a>) не работал, а на сайте организации – правообладателя (<a href="https://icl.ru" target="_blank">https://icl.ru</a>) не было сведений о данной операционной системе. Поэтому ICLinux в итоге не вошла в список рассматриваемых при выборе решений операционных систем.</p>
  <p id="unx9"><strong>Характеристика линейки рассматриваемых ОС. </strong>Следует начать с того, что все рассматриваемые операционные системы – разновидности операционной системы GNU/Linux, разрабатываемой международным сообществом на принципах свободного программного обеспечения. Это является преимуществом для разработчиков ПО, так как все эти операционные системы по большей части совместимы между собой и поддерживают различное серверное ПО, средства виртуализации, SMB-протокол, СУБД, офисные и мультимедийные программы, а также большой спектр стороннего ПО и оборудования.</p>
  <p id="Q4g9">Ниже приведены рассматриваемые продукты:</p>
  <p id="r4yQ">1) ОСнова – дистрибутив Linux, основанный на Debian и разрабатываемый АО «НППКТ»;</p>
  <p id="0Yd6">2) РЕД ОС – дистрибутив Linux, основанный на CentOS и разрабатываемый компанией «РЕД СОФТ»;</p>
  <p id="RdZ4">3) ALT Linux – дистрибутив Linux, изначально основывающийся на MandrakeLinux, ныне являющийся отдельной ветвью развития Linux и разрабатываемый компаниями «Базальт СПО»;</p>
  <p id="G9Tm">4) Astra Linux – дистрибутив Linux, основанный на Debian и разрабатываемый компанией «НПО РусБИТех», а затем – «РусБИТех-Астра»;</p>
  <p id="Amrs">5) ROSA Linux – дистрибутив Linux, основанный на Mandriva и разрабатываемый компанией «НТЦ ИТ РОСА».</p>
  <p id="SAWl"><strong>Определение критериев выбора.</strong> В государственном секторе намечается тенденция к импортозамещению в аппаратной составляющей компьютеров [4, 6, 8]. Поскольку в большинстве своём системы совместимы (РЕД ОС, ALT Linux и ROSA Linux используют пакетную базу RPM, Astra Linux – официальный дериватив Debian, а «ОСнова» также использует пакетную базу Debian), единственным критерием, по которому мы можем оценить систему, – это поддержка архитектур процессоров.</p>
  <p id="NbaT">Архитектура x86_64, также известная как AMD64 или Intel 64, является одной из самых распространенных архитектур для персональных компьютеров и серверов. Она разработана компаниями Intel и AMD и представляет собой развитие архитектуры x86. Использует 64-битные инструкции, что позволяет обрабатывать большие объемы данных и обеспечивает поддержку большего объёма памяти (более 4 ГБ). Это позволяет компьютерам выполнять сложные задачи, такие как анализ данных, моделирование и обработка мультимедийного контента.</p>
  <p id="5IJ5">Архитектура aarch64, известная также как ARM64, разработана компанией ARM и широко используется в современных мобильных устройствах, планшетах, смартфонах и других энергоэффективных устройствах. Она основана на 64-битной инструкционной системе ARM, что позволяет устройствам эффективно использовать энергию и работать дольше от батареи. Архитектура aarch64 стала предпочтительным выбором для мобильных устройств и интернета вещей, где энергоэффективность играет важную роль.</p>
  <p id="kxg2">Архитектура «Эльбруса» представляет собой российскую разработку, призванную обеспечить импортозамещение и независимость в сфере информационных технологий. Эти процессоры разрабатываются компанией «МЦСТ». Архитектура «Эльбрус» также поддерживает 64-битные инструкции и предназначена для использования в высокопроизводительных системах и решениях информационной безопасности.</p>
  <p id="45iD">Ниже приведены условные баллы поддержки архитектур процессоров:</p>
  <ul id="mWOY">
    <li id="tEzf">1 балл – поддержка классической архитектуры x86_64;</li>
    <li id="gogW">2 балла – вышеупомянутое, а также поддержка дополнительных архитектур, в том числе мобильной архитектуры aarch64 (armv8);</li>
    <li id="yEvV">3 балла – вышеупомянутое, а также поддержка отечественных архитектур процессоров, например, «Эльбрус».</li>
  </ul>
  <p id="uMv1">Федеральная служба технического и экспортного контроля регулирует применение ПО, в том числе ОС, в защищаемых информационных системах. Помимо этого, вендоры операционных систем могут также разрабатывать свои решения и встраивать их в свою продукцию. </p>
  <p id="qODd">Ниже представлены условные баллы защищённости:</p>
  <ul id="PiuT">
    <li id="N5Lg">1 балл – средняя защита (сертификат соответствия ФСТЭК – минимум ИТ.ОС.А4.П3);</li>
    <li id="Izei">2 балла – средняя защита + любые дополнительные программные средства защиты информации, разрабатываемые вендором;</li>
    <li id="C8Vb">3 балла – высокий уровень защиты (сертификат соответствия ФСТЭК – ИТ.ОС.А1.П3).</li>
  </ul>
  <p id="AlQS">Для того, чтобы устанавливать операционные системы и обслуживать и администрировать компьютеры с ними, необходимы специалисты. Более того, для бизнеса и в особенности для государственного сектора требуются сертифицированные специалисты.  Процедура сертификации системных администраторов условно выглядит следующим образом:</p>
  <ul id="JXlP">
    <li id="o4oA">Обучение работе с целевой администрируемой системой по специальному курсу.</li>
    <li id="s9lG">Прохождение тестирования на знание методологии и особенностей администрирования.</li>
    <li id="EU4L">Получение сертификата.</li>
  </ul>
  <p id="9Q53">Ниже приведены условные баллы затрат на подготовку специалистов, которые показывают разницу в 40-60% от стоимости подготовки и сертификации:</p>
  <ul id="dnBJ">
    <li id="scGp">1 балл – высокая стоимость;</li>
    <li id="qhbC">2 балла – невысокая стоимость.</li>
  </ul>
  <p id="ylTf">По причине необходимости получения заново через определённое время сертификата соответствия ФСТЭК, а также с целью исправления проблем, которые могут быть обнаружены в процессе эксплуатации ОС, необходимо, чтобы компания функционировала как можно стабильнее и могла обеспечивать поддержку и развитие ОС после внедрения на предприятии. Ниже приведены условные баллы, характеризующие уровень экономической устойчивости:</p>
  <ul id="a0OK">
    <li id="Heof">0 баллов – кризисное положение;</li>
    <li id="lQ4G">1 балл – низкий уровень устойчивости;</li>
    <li id="XDik">2 балла – средний уровень устойчивости;</li>
    <li id="jkkp">3 балла – высокий уровень устойчивости.</li>
  </ul>
  <h2 id="BbRt">Результаты и их обсуждение</h2>
  <p id="YKv3"><strong>Поддержка аппаратного обеспечения.</strong> В таблице 1 приведены поддерживаемые архитектуры процессоров и присвоенные на основании оценки архитектур баллы.</p>
  <figure id="mgtl" class="m_original">
    <img src="https://img4.teletype.in/files/f8/a7/f8a7a003-73a7-42f2-9979-68512d444904.png" width="674" />
  </figure>
  <p id="7ClC">Из таблицы 1 мы можем сделать вывод, что ALT Linux и Astra Linux более подготовлены к этому переходу, что, в свою очередь, напрямую повлияет на доступность локализированной вычислительной техники. Также, если предприятие использует какие-то специфические аппаратные архитектуры процессоров, ALT и Astra имеют возможность покрыть те архитектуры при переходе, которые не смогут покрыть РЕД ОС и ROSA Linux.</p>
  <p id="muR5"><strong>Характеристики и оценка программных возможностей защиты информации.</strong> Использование защищённых операционных систем в экосистеме компании имеет фундаментальное значение для обеспечения безопасности, стабильности и надёжности работы компании. Защищенные операционные системы предназначены для предотвращения и ограничения атак со стороны злонамеренных акторов, таких как хакеры, вредоносные программы и киберпреступники. Такие системы обладают многоуровневыми механизмами безопасности, которые позволяют выявлять и блокировать угрозы до того, как они станут критическими проблемами для компании или инфраструктуры. Помимо этого, они обеспечивают защиту конфиденциальной информации, обеспечивают изоляцию и ограничение прав доступа для приложений, помогают предотвращать отказы и сбои. Это особенно важно для компаний, которые обрабатывают конфиденциальную информацию или являются объектами критической инфраструктуры. Компрометация операционных систем может привести к серьезным уязвимостям, эксплуатации системы и потере контроля над данными и инфраструктурой, поэтому использование защищенных операционных систем является критическим аспектом.</p>
  <p id="Y29L">В таблице 2 приведены решения, созданные и/или применяемые в программных продуктах и связанные с защитой информации, а также информация о сертификатах соответствия ФСТЭК для конкретных редакций дистрибутивов и условные баллы защищённости.</p>
  <figure id="cv0s" class="m_original">
    <img src="https://img1.teletype.in/files/48/91/4891c582-8e1e-4582-b4aa-00173f3f6259.png" width="634" />
  </figure>
  <p id="HWat"><strong>Стоимость подготовки специалистов-администраторов.</strong> На данный момент существуют программы сертификации и обучения специалистов для администрирования всех сравниваемых ОС, кроме «ОСнова». Сертификация и обучение для ALT Linux составляет 25 тыс. руб., РЕД ОС – 28-31 тыс. руб., ROSA Linux – 20 тыс. руб., Astra Linux – 36-60 тыс. руб.[5, 7]</p>
  <figure id="vWqv" class="m_original">
    <img src="https://img1.teletype.in/files/42/69/42699ed8-bd28-43a4-96e6-5624c73d3713.png" width="625" />
  </figure>
  <p id="F8zt"><strong>Уровень экономической устойчивости. </strong>Оценка экономического положения организаций – разработчиков сравниваемых операционных систем позволяет сделать прогноз относительно уровня стабильности поддержки рассматриваемых в работе операционных систем в дальнейшем.</p>
  <p id="kOPB">Необходимо отметить, что задача оценки экономической устойчивости организаций - разработчиков операционных систем и в целом, организаций, работающих в области разработки компьютерного программного обеспечения и консалтинга в данной области, пока является нерешенной. Один из вариантов решения, примененный авторами, предполагает подход, обратный оценке экономической устойчивости, и применение моделей, характеризующих уровень финансовой состоятельности при оценке вероятности банкротства организаций. Использование такого подхода требует вдумчивого выбора наиболее подходящих для решения подобной задачи моделей оценки финансовой состоятельности.</p>
  <p id="pjIx">Для выбора моделей и принимая во внимание особенности экономического содержания моделей, опирающихся на показатели бухгалтерской отчетности, характеризующие финансовое положение организаций, следует обратиться к используемым в разных моделях страновым, отраслевым и временным выборкам. И здесь мы увидим ряд моделей, обладающих широкой известностью и высокой популярностью, которые построены на данных американских рынков в пределах относительно узких временных периодов. Это связано, отчасти и с тем, что интерес к решению задач прогнозирования вероятности банкротства становится высоким в тех случаях, когда сама вероятность банкротства организаций тоже повышается, то есть в периоды экономических кризисов и в первые посткризисные годы. Вторая особенность обсуждаемых моделей, заключается в довольно широких отраслевых выборках. Так, классическая пятифакторная дискриминантная модель Альтмана построена на данных публичных акционерных компаний. Более адекватными для решаемой в работе цели оценки являются дискриминантные модели, построенные на данных, характеризующих деятельность непроизводственных компаний американского рынка, и на данных, характеризующих деятельность компаний на развивающихся рынков. В последней модели используется повышающий коэффициент, отражающий более высокую нестабильность развивающихся рынков в целом.</p>
  <p id="ghKp">Для компенсации указанных выше недостатков авторы обратились и к моделям финансовой состоятельности, построенным на данных организаций отечественной экономики. Однако здесь мы были вынуждены отметить незначительное количество исследований, посвященных отражению отраслевой специфики организаций. За более чем десятилетний период проблемам оценки вероятности банкротства компаний было посвящено около ста научных работ, при этом отраслевая специфика рассматривается в примерно четверти из них, а особенности оценки финансовой стабильности и вероятности банкротства предприятий ИТ-сферы не рассматриваются ни в одной из них. Принимая во внимание указанные факты, авторы для оценки выбрали универсальную модель, обладающую достаточным уровнем достоверности прогноза и разработанную на данных организаций, выборка которых соответствует отраслевой структуре российской экономики [2].</p>
  <p id="L1Wp">Таким образом, в основу оценки экономической устойчивости организаций была положена комплексная оценка финансовой состоятельности, выполненная по трем моделям: дискриминантным моделям Альтмана для непроизводственных компаний (Z-score) и для развивающихся рынков (EM Z-score), а также по логит-модели О. Е. Большаковой [2].</p>
  <p id="iU47">Выбранные для оценки модели демонстрируют низкую вероятность ошибки прогноза отсутствия банкротства компании - 0,006 [1], то есть позволяют с высокой степенью точности определить стабильность состояния компании. Оценка финансовой устойчивости компаний выполнена в динамике за 2019-2022 гг. Данные для оценки взяты из открытых источников.</p>
  <p id="9GJG">При интерпретации результатов в дискриминантных моделях используется стандартное значение индекса – 2,6.</p>
  <p id="uuaB">При интерпретации результатов оценки логит-модели введен ограничивающий оценку критерий – 0,25. Полученные значения логит-модели ниже 0,25 трактуются как характеристика финансово устойчивого положения компании.</p>
  <p id="uZ8B">В таблицах 4-6 представлены результаты расчетов индексов и оценок по выбранным для комплексной оценки финансовой состоятельности организаций - разработчиков программного обеспечения моделей.</p>
  <p id="XPmN">Отметим, что ООО «НТЦ ИТ РОСА»перешло в 2022 г. на упрощенную систему налогообложения, что ограничило возможности оценки по данным открытых источников. Это специфическое положение организации отмечено в таблицах 4-6*. О компаниях АО «НППКТ» и ООО «РусБИТех-Астра» в открытых источниках, публикующих сведения о финансовой отчетности организаций по данным Федеральной налоговой службы, сведения на момент проведения исследования отсутствуют, что может быть связано с особыми условиями функционирования этих организаций и использования разрабатываемых ими решений, поэтому при оценке мы опирались на данные отчетности за предшествующие годы. Эти особенности отмечены в таблицах 4-6**.</p>
  <figure id="zYiW" class="m_original">
    <img src="https://img2.teletype.in/files/11/74/1174384c-12a5-47d8-bf83-64040c40decd.png" width="513" />
  </figure>
  <p id="zsbW">В таблице 5 представлен результат расчета индекса дискримиантной модели, разработанной для оценки финансовой состоятельности организаций, работающих на развивающихся рынках. Особенностью данной модели является отражение более высокую нестабильность, характерную для развивающихся рынков.</p>
  <p id="xcGX">Анализ представленных в таблице результатов позволяет сделать вывод о высоком уровне финансовой устойчивости представленных в обзоре организаций. Положение только одной организации - ООО «НТЦ ИТ РОСА» является неустойчивым на протяжении всего периода, при этом динамика индекса свидетельствует об улучшении финансового состояния организации.</p>
  <figure id="Jn9L" class="m_original">
    <img src="https://img4.teletype.in/files/75/79/7579a341-9fe1-4a4a-9a32-ac3d28b37015.png" width="513" />
  </figure>
  <p id="WW89">В таблице 6 представлены оценки логит-модели для анализируемых в работе компаний - разработчиков программного обеспечения. Итоговая оценка принимается на основе рассчитанного за представленный временной диапазон среднего значения оценки и сопоставления его с критическим значением, выбранным для данной модели.</p>
  <p id="QBMD">Особенностью данной логит-модели [2], является использование динамических показателей. Так, для оценки используется показатель средней кредиторской задолженности. Такая логика расчета потребовала от авторов расширения диапазона данных, в расчетах, в частности, использовались данные за 2018 г.</p>
  <figure id="s4sg" class="m_original">
    <img src="https://img4.teletype.in/files/7c/0a/7c0aa394-dee8-4bd5-b522-a5e4c963919b.png" width="521" />
  </figure>
  <p id="bvZg">Отметим, что для большинства анализируемых организаций положение стабильно в течение всего рассматриваемого периода. ООО «Ред Софт» и ООО «Базальт СПО» демонстрируют финансовую устойчивость при оценке их положения каждой из моделей. Положение ООО «НТЦ ИТ РОСА» является критическим на протяжении всего рассматриваемого периода, но при этом по результатам оценки с использованием дискриминантных моделей организация демонстрирует положительную динамику индексов, значение EM Z-score по результатам 2021 г. приближается к пороговому значению, а при оценке с помощью логит-модели мы видим ухудшение финансового положения организации и повышение риска банкротства.</p>
  <p id="K3z8">В таблице 7 указано усредненное значение оценки и посчитаны условные баллы, характеризующие результат проведенной комплексной оценки финансового положения организаций.</p>
  <p id="fuUd">Условные баллы определены как сумма интерпретируемых значений трех моделей, при этом в каждом случае при достижении необходимого значения показателя присваивается оценка «1», в противном случае – «0».</p>
  <figure id="oANd" class="m_original">
    <img src="https://img4.teletype.in/files/3c/11/3c11de2b-adee-40e8-b648-9b02d3f1c5cb.png" width="510" />
  </figure>
  <p id="mtdj"><strong>Распределение условных баллов.</strong> В таблице 8 приведено распределение условных баллов по операционным системам. В таблицу включены выше разработанные критерии оценки и выполненные в ходе работы оценки по балльным шкалам. По каждому частному критерию оценки, расчеты по которым представлены в таблицах 1-7, представлены баллы. В строке «Итого» суммируются баллы по частным критериям для каждой операционной системы. Наиболее предпочтительными для выбора являются операционные системы, по которым получены максимальные итоговые значения баллов.</p>
  <figure id="J1vT" class="m_original">
    <img src="https://img1.teletype.in/files/02/18/02181559-0deb-47ed-a6b4-eddeba6fe4ca.png" width="496" />
  </figure>
  <h2 id="keA3">Заключение</h2>
  <p id="024g">В результате сравнения операционных систем наиболее предпочтительным представляется выбор среди двух вариантов: ALT Linux и Astra Linux. При этом выбор может быть скорректирован с учётом поставленных перед организацией задач: так, например, с точки зрения средств программной защиты информации безусловным лидером выходит Astra Linux, которая имеет сертификацию ФСТЭК для обработки совершенно секретной информации (ИТ.ОС.А1.П3), что выступает важным критерием для применения ОС на предприятиях – объектах КИИ и в государственных органах. В то же время стоимость подготовки специалистов администрирования для ALT Linux существенно ниже, а класс защиты вполне приемлемый для бизнеса.</p>
  <p id="WmNx">При этом, несмотря на наличие дополнительных встраиваемых программных средств защиты информации в «ОСнова» и ROSA Linux, надо принимать во внимание, что для первой ОС нет программ сертификации специалистов, а экономическое положение организации-разработчика второй характеризуется как кризисное.</p>
  <p id="gV1Z">Разработанный алгоритм и критерии выбора операционных систем помогает принять решение о выборе операционной системы, внедрение и эксплуатация которой наиболее полно отвечает потребностям и перспективам развития организации, с учётом того, что все представленные в анализе решения отвечают минимальным требованиям регуляторов.</p>
  <h2 id="6Gzp">Литература</h2>
  <ol id="67gv">
    <li id="eou4">Березинец И. В., Бобылева А. З., Ильина Ю. Б. Вероятность банкротства: достоверны ли модели прогнозирования? // Государственное управление. Электронный вестник. 2022. №94.</li>
    <li id="SBCC">Большакова О. Е., Максимов А. Г., Максимова Н. В. О моделях диагностики состоятельности предприятий малого и среднего бизнеса // Вестник ВГУ. Серия: Экономика и управление. 2014. №3.</li>
    <li id="nDM4">ИТ-курсы по вендорам. [Электронный ресурс]. Режим доступа: <a href="https://edu.softline.com/vendors/" target="_blank">https://edu.softline.com/vendors/</a> (дата обращения: 10.05.2023).</li>
    <li id="nsh3">Корпорация «Тактическое ракетное вооружение»: импортозамещение программного обеспечения идет успешно [Электронный ресурс]. Режим доступа: <a href="https://2009-2020.oborona.ru/includes/periodics/defense/2020/0117/173128505/detail.shtml" target="_blank">https://2009-2020.oborona.ru/includes/periodics/defense/2020/0117/173128505/detail.shtml</a> (дата обращения: 16.05.2023).</li>
    <li id="RbhV">Перечень курсов Академии информационных систем. [Электронный ресурс]. Режим доступа: <a href="https://www.infosystems.ru/about/price/" target="_blank">https://www.infosystems.ru/about/price/</a> (дата обращения: 15.05.2023).</li>
    <li id="tiqN">Полное импортозамещение: производство отечественных процессоров Эльбрус хотят перенести из Тайваня в Россию. [Электронный ресурс]. Режим доступа: <a href="https://www.ferra.ru/news/techlife/polnoe-importozameshenie-proizvodstvo-otechestvennykh-processorov-elbrus-khotyat-perenesti-iz-taivanya-v-rossiyu-30-05-2022.htm" target="_blank">https://www.ferra.ru/news/techlife/polnoe-importozameshenie-proizvodstvo-otechestvennykh-processorov-elbrus-khotyat-perenesti-iz-taivanya-v-rossiyu-30-05-2022.htm</a> (дата обращения: 15.05.2023).</li>
    <li id="Gwo7">Работа в России, поиск персонала и публикация вакансий. [Электронный ресурс]. Режим доступа: <a href="https://hh.ru/search/vacancy?area=113&professional_role=113&professional_role=116&professional_role=114&professional_role=121&search_field=name&search_field=company_name&search_field=description&enable_snippets=false&text=Astra+Linux&ored_clusters=true" target="_blank">https://hh.ru/search/vacancy?area=113&amp;professional_role=113&amp;professional_role=116&amp;professional_role=114&amp;professional_role=121&amp;search_field=name&amp;search_field=company_name&amp;search_field=description&amp;enable_snippets=false&amp;text=Astra+Linux&amp;ored_clusters=true</a> (дата обращения: 10.05.2023).</li>
    <li id="em9I">Разработчик «Эльбруса» оценил поправки в документ об импортозамещении. [Электронный ресурс]. Режим доступа: <a href="https://www.ferra.ru/news/techlife/polnoe-importozameshenie-proizvodstvo-otechestvennykh-processorov-elbrus-khotyat-perenesti-iz-taivanya-v-rossiyu-30-05-2022.htm" target="_blank">https://www.ferra.ru/news/techlife/polnoe-importozameshenie-proizvodstvo-otechestvennykh-processorov-elbrus-khotyat-perenesti-iz-taivanya-v-rossiyu-30-05-2022.htm</a> (дата обращения: 15.05.2023).</li>
    <li id="Gceb">Распоряжение Правительства РФ от 28.07.2017 N 1632-р «Об утверждении программы «Цифровая экономика Российской Федерации».</li>
    <li id="FNWU">Реестр российского программного обеспечения. [Электронный ресурс]. Режим доступа: <a href="https://reestr.digital.gov.ru/" target="_blank">https://reestr.digital.gov.ru/</a> (дата обращения: 04.07.2023).</li>
    <li id="cYeA">Титов К. А., Водяницкая С. И. Концептуальные подходы к сравнению российских операционных систем с открытым кодом // Научные исследования 2023: актуальные теории и концепции : сборник материалов XXIX-ой международной очно-заочной научно-практической конференции, Москва, 24 мая 2023 года. Том 1. – Москва: Научно-издательский центр «Империя», 2023. – С. 39-43. – EDN FJMJAT</li>
    <li id="iv9b">Указ Президента Российской Федерации от 01.05.2022 г. № 250 «О дополнительных мерах по обеспечению информационной безопасности Российской Федерации».</li>
    <li id="K0Oz">Указ Президента РФ «Вопросы Федеральной службы по техническому и экспортному контролю» от 16.08.2004 №1085.</li>
  </ol>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@titoffklim/arch-luks2-btrfs-grub-efi</guid><link>https://teletype.in/@titoffklim/arch-luks2-btrfs-grub-efi?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim</link><comments>https://teletype.in/@titoffklim/arch-luks2-btrfs-grub-efi?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim#comments</comments><dc:creator>titoffklim</dc:creator><title>Arch + LUKS2 + Btrfs + GRUB-on-EFI Installation</title><pubDate>Sun, 14 May 2023 19:04:32 GMT</pubDate><category>Код</category><description><![CDATA[На данном этапе требуется создать два раздела на имеющихся у вас накопителях: один - для EFI, другой - для системы. Диск следует разметить как GPT.]]></description><content:encoded><![CDATA[
  <h3 id="Этап-первый.-Разметка-диска">Этап первый. Разметка диска</h3>
  <p id="LrsV">На данном этапе требуется создать два раздела на имеющихся у вас накопителях: один - для EFI, другой - для системы. Диск следует разметить как GPT.</p>
  <p id="BmzW">Вики: <a href="https://wiki.archlinux.org/title/fdisk" target="_blank">https://wiki.archlinux.org/title/fdisk</a></p>
  <h3 id="Этап-второй.-Создание-разделов">Этап второй. Создание разделов</h3>
  <p id="0fjJ"><code># mkfs.vfat -F32 /dev/{EFI-раздел}</code></p>
  <p id="GwwX"><code># cryptsetup --key-size 512 --hash sha512 luksFormat /dev/{системный раздел}</code></p>
  <p id="sLbI"><code># cryptsetup open /dev/{системный раздел} root</code></p>
  <p id="p3SV"><code># mkfs.btrfs /dev/{системный раздел}</code></p>
  <p id="3HfB"><code># mount -o compress-force=zstd:4 /dev/{системный раздел} /mnt</code></p>
  <p id="hGUg"><code># mount --mkdir /dev/{раздел EFI} /mnt/boot/efi</code></p>
  <h3 id="Этап-третий.-Установка-пакетов-и-настройка-системы">Этап третий. Установка пакетов и настройка системы</h3>
  <p id="t2Zv"><code># pacman -Sy reflector</code></p>
  <p id="HMwK"><code># reflector --save /etc/pacman.d/mirrorlist --latest 5 --country Russia --protocol https</code></p>
  <p id="WFd5"><code># pacstrap -K /mnt base base-devel {ядро, например, linux} linux-firmware efibootmgr {менеджер сети, например, networkmanager} {текстовый редактор, например, nano}</code></p>
  <p id="vQYi"><code># genfstab -U /mnt &gt; /mnt/etc/fstab</code></p>
  <p id="AfXM"><code># arch-chroot /mnt</code></p>
  <p id="C0Tl"><code># nano /etc/locale.gen</code></p>
  <p id="gguk">Выбираем нужные нам локали и запускаем далее:</p>
  <p id="807a"><code># locale-gen</code></p>
  <p id="JpO5"><code># echo LANG={локаль, например, en_US.UTF-8} &gt; /etc/locale.conf</code></p>
  <p id="vDYo"><code># ln -sf /usr/share/zoneinfo/{регион}/{город} /etc/localtime</code></p>
  <p id="x8fd"><code># hwclock --systohc --utc</code></p>
  <p id="MTMF"><code># echo {имя хоста} &gt; /etc/hostname</code></p>
  <p id="Mxy0"><code># nano /etc/hosts</code></p>
  <p id="yyoY">Пишем:<br /><em>127.0.0.1 localhost {имя хоста}<br />:: 1 localhost {имя хоста}</em></p>
  <p id="K6d0"><code># systemctl enable NetworkManager</code></p>
  <p id="SfHv"><code># dd bs=512 count=4 if=/dev/urandom of=/crypto_keyfile.bin</code></p>
  <p id="tiBd"><code># cryptsetup luksAddKey /dev/{системный раздел} /crypto_keyfile.bin</code></p>
  <p id="DmUf"><code># chmod 600 /crypto_keyfile.bin</code></p>
  <p id="ERdD">Нам потребуется вручную собрать загрузчик, поэтому выбираем yay из любого репозитория: <a href="https://pkgs.org/search/?q=yay" target="_blank">https://pkgs.org/search/?q=yay</a></p>
  <p id="Rj4z"><code># curl {ссылка на yay из одного из репозиториев, например, https://arch.alerque.com/x86_64/yay-12.0.4-1-x86_64.pkg.tar.zst}</code></p>
  <p id="3QqN"><code># pacman -U {имя файла пакета, например, yay-12.0.4-1-x86_64.pkg.tar.zst}</code></p>
  <p id="LkdS"><code># passwd</code></p>
  <p id="S9vk"><code># useradd -m {имя пользователя}</code></p>
  <p id="mDGS"><code># passwd {имя пользователя}</code></p>
  <p id="z6YT"><code># EDITOR=nano visudo</code></p>
  <p id="SI6p">Вписываем после строки<br /><em>root ALL=(ALL:ALL) ALL</em><br />строку:<br /><em>{имя пользователя} ALL=(ALL:ALL) ALL</em></p>
  <p id="Ampy"><code># sudo -iu {имя пользователя}</code></p>
  <p id="U4jk"><code>$ yay -S grub-improved-luks2-git</code></p>
  <p id="41Gn"><code>$ sudo nano /etc/mkinitcpio.conf</code></p>
  <p id="Znq4">Редактируем следующие строки:<br /><em>MODULES=(btrfs vfat)<br />FILES=(/crypto_keyfile.bin)<br />HOOKS=(base udev autodetect modconf kms keyboard keymap block encrypt filesystems fsck)</em></p>
  <p id="d9UO"><code>$ sudo mkinitcpio -P</code></p>
  <p id="xwP1"><code>$ sudo chmod 600 /boot/initramfs-linux*</code></p>
  <p id="HHEe"><code>$ sudo nano /etc/default/grub</code></p>
  <p id="hZDy">Редактируем следующие строки:<br /><em>GRUB_CMDLINE_LINUX=&quot;cryptdevice=UUID={UUID системного раздела, смотрим через команду &quot;lsblk -f&quot;}:root root=/dev/mapper/root&quot;</em><br /><em>GRUB_ENABLE_CRYPTODISK=y</em></p>
  <p id="f0p1"><code>$ sudo grub-mkconfig -o /boot/grub/grub.cfg</code></p>
  <p id="e29p"><code>$ sudo grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=GRUB</code></p>
  <p id="W93h"><code>$ sudo nano /boot/grub/grub-pre.cfg</code></p>
  <p id="zTcx">Пишем:<br /><em>set crypto_uuid={UUID системного раздела}<br />cryptomount -u $crypto_uuid<br />set root=crypto0<br />set prefix=($root)/boot/grub<br />insmod normal<br />normal</em></p>
  <p id="HAc7"><code>$ grub-mkimage -p /boot/grub -O x86_64-efi -c /boot/grub/grub-pre.cfg -o /tmp/grubx64.efi luks2 part_gpt cryptodisk gcry_rijndael gcry_sha512 argon2 btrfs</code></p>
  <p id="DlPh"><code>$ sudo install -v /tmp/grubx64.efi /boot/efi/EFI/GRUB/grubx64.efi</code></p>
  <p id="t3x3">После этого, дважды нажав Ctrl+D, выходим в консоль archiso и вводим:</p>
  <p id="ewTB"><code># umount -R /mnt</code></p>
  <p id="JCIT"><code># reboot</code></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@titoffklim/career-start</guid><link>https://teletype.in/@titoffklim/career-start?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim</link><comments>https://teletype.in/@titoffklim/career-start?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim#comments</comments><dc:creator>titoffklim</dc:creator><title>Сборник ресурсов для карьерного старта и роста</title><pubDate>Thu, 20 Apr 2023 14:49:20 GMT</pubDate><category>Дело и проекты</category><description><![CDATA[Если вы хотите добавить в сборник свой ресурс, пишите в комментарии.]]></description><content:encoded><![CDATA[
  <p id="gmzh"><em>Если вы хотите добавить в сборник свой ресурс, пишите в комментарии.</em></p>
  <h2 id="3kSO">0. Обучение</h2>
  <h3 id="HL1W">0.1. IT-ресурсы</h3>
  <p id="6jpJ"><a href="https://t.me/it_tochka" target="_blank">https://t.me/it_tochka</a> - точка входа в IT</p>
  <p id="06C5"><a href="https://t.me/habr_com" target="_blank">https://t.me/habr_com</a> - <s>без комментариев</s> канал лучшего айтишного сайта Рунета</p>
  <p id="1GPg"><a href="https://t.me/it_chats" target="_blank">https://t.me/it_chats</a> - чаты в Телеграме по разным технологиям, языкам программирования, вакансиям и прочему</p>
  <p id="RBPh"><a href="https://t.me/sec_devops" target="_blank">https://t.me/sec_devops</a> - канал, в котором публикуются материалы о выстраивании безопасного DevOps</p>
  <p id="Xvvm"><a href="https://t.me/structuredata" target="_blank">https://t.me/structuredata</a> - всё про алгоритмы и структуры данных</p>
  <p id="tTvp"><a href="https://t.me/seniorFront" target="_blank">https://t.me/seniorFront</a> - всё для фронтенда</p>
  <p id="upVl"><a href="https://t.me/it_guides" target="_blank">https://t.me/it_guides</a> - гайды программиста</p>
  <p id="ZrPX"><a href="https://t.me/physics_lib" target="_blank">https://t.me/physics_lib</a> - книжки для технарей</p>
  <p id="5XIu"><a href="https://t.me/eda_shad" target="_blank">https://t.me/eda_shad</a> - чатик от ЕДА</p>
  <p id="5g1E"><a href="https://t.me/devo_pes" target="_blank">https://t.me/devo_pes</a> - DevOps для девопсов</p>
  <p id="i7Qz"><a href="https://t.me/cm_books" target="_blank">https://t.me/cm_books</a> - литература для разработчиков, ещё есть <a href="https://t.me/+fVscRbjiGfVkODgy" target="_blank">https://t.me/+fVscRbjiGfVkODgy</a></p>
  <p id="XNCv"><a href="https://t.me/proglibrary" target="_blank">https://t.me/proglibrary</a> - библиотека программиста</p>
  <p id="RPai"><a href="https://t.me/gebutcher/8232" target="_blank">https://t.me/gebutcher/8232</a> - ИБ-телега</p>
  <h3 id="StNC">0.2. Ресурсы для бизнеса, финансов, маркетинга и связанного</h3>
  <p id="Avvk"><a href="https://t.me/markettwits" target="_blank">https://t.me/markettwits</a> - оперативные краткие новости из финансового сектора</p>
  <p id="oHEg"><a href="https://t.me/forbesrussia" target="_blank">https://t.me/forbesrussia</a> - канал русского Forbes</p>
  <p id="F1Vw"><a href="https://t.me/business_ru" target="_blank">https://t.me/business_ru</a> - бизнес в одном месте</p>
  <p id="aqQj"><a href="https://t.me/joinchat/AAAAAFgITvCoA4h2nuug8A" target="_blank">https://t.me/joinchat/AAAAAFgITvCoA4h2nuug8A</a> - &quot;Анонсируем различные курсы, лекции, марафоны, сообщаем о различных форумах и образовательных программах&quot;</p>
  <p id="oEmR"><a href="https://t.me/creativestar" target="_blank">https://t.me/creativestar</a> - современный маркетинг, ещё есть <a href="https://t.me/sell_me" target="_blank">https://t.me/sell_me</a> и <a href="https://t.me/marketingold" target="_blank">https://t.me/marketingold</a></p>
  <p id="1gyo"><a href="https://t.me/digital_review" target="_blank">https://t.me/digital_review</a> - тренды</p>
  <p id="izDe"><a href="https://t.me/remingtonist" target="_blank">https://t.me/remingtonist</a> - карты, тексты, два ствола</p>
  <p id="AYK5"><a href="https://t.me/ludobreniya" target="_blank">https://t.me/ludobreniya</a> - бренды и пиар</p>
  <p id="TH50"><a href="https://t.me/finside" target="_blank">https://t.me/finside</a> - банки, инвестиции, финтех, ещё есть <a href="https://t.me/Coin_Post" target="_blank">https://t.me/Coin_Post</a></p>
  <p id="ZKRh"><a href="https://t.me/investfuture" target="_blank">https://t.me/investfuture</a> - медиа про деньги</p>
  <p id="sFjH"><a href="https://t.me/illyuziya_obmana_risk_menedjment" target="_blank">https://t.me/illyuziya_obmana_risk_menedjment</a> - риск-менеджмент</p>
  <p id="X8Le"><a href="https://t.me/economika" target="_blank">https://t.me/economika</a> - экономика</p>
  <p id="yfjW"><a href="https://t.me/vcnews" target="_blank">https://t.me/vcnews</a> - &quot;Бизнес, технологии, идеи, модели роста.&quot;</p>
  <p id="t9rS"><a href="https://t.me/epicgrowth" target="_blank">https://t.me/epicgrowth</a> - рост продуктов, ещё есть <a href="https://t.me/product_and_project" target="_blank">https://t.me/product_and_project</a></p>
  <p id="rPvy"><a href="https://t.me/bizcult" target="_blank">https://t.me/bizcult</a> - бизнес-культура</p>
  <h3 id="KDWB">0.3. Ресурсы для дизайнеров</h3>
  <p id="23zL"><a href="http://t.me/+2BgCKREek4Y4YzI6" target="_blank">http://t.me/+2BgCKREek4Y4YzI6</a> - шрифты для коммерческого и личного использования</p>
  <p id="IYSp"><a href="https://t.me/Figmachex" target="_blank">https://t.me/Figmachex</a> - Фигмач</p>
  <p id="nERI"><a href="https://t.me/onbehancer" target="_blank">https://t.me/onbehancer</a> - лучшее с Behance, ещё есть <a href="https://t.me/+ImpMwqnYaQY0OTYy" target="_blank">https://t.me/+ImpMwqnYaQY0OTYy</a></p>
  <p id="iue2"><a href="https://t.me/figma2html" target="_blank">https://t.me/figma2html</a> - макеты для вёрстки, ещё есть <a href="https://t.me/true_figma" target="_blank">https://t.me/true_figma</a></p>
  <p id="Tx1l"><a href="https://t.me/TheDesignus" target="_blank">https://t.me/TheDesignus</a> - Дизайнус</p>
  <h3 id="nm2M">0.4. Саморазвитие</h3>
  <p id="rKPw"><a href="https://t.me/Chitat_onlain_Biblioteka" target="_blank">https://t.me/Chitat_onlain_Biblioteka</a> - книги по саморазвитию</p>
  <p id="yK01"><a href="https://t.me/bezaspera" target="_blank">https://t.me/bezaspera</a> - &quot;Меня зовут Арина Хромова, я карьерный эксперт и сооснователь <a href="https://t.me/careerspace" target="_blank">@careerspace</a>. Пишу о карьере, управлении командами и стартапах.&quot;</p>
  <h2 id="g2nc">1. Резюме</h2>
  <p id="vT3A"><a href="https://rxresu.me/" target="_blank">https://rxresu.me/</a> - создаёт резюме из текста</p>
  <p id="gLSy"><a href="https://t.me/resume_review" target="_blank">https://t.me/resume_review</a> - группа, где могут проверить ваше резюме</p>
  <h2 id="ng96">2. Вакансии и стажировки</h2>
  <p id="7uo0"><a href="https://t.me/changellenge" target="_blank">https://t.me/changellenge</a> - главный ресурс топовых вакансий в российских компаниях. <a href="https://changellenge.com/" target="_blank">https://changellenge.com/</a> - сайт Changellenge</p>
  <p id="W6b2"><a href="https://t.me/appsec_job" target="_blank">https://t.me/appsec_job</a> - работы в сфере информационной безопасности (AppSec + DevSecOps). Ещё есть <a href="https://t.me/RuSecJobs" target="_blank">https://t.me/RuSecJobs</a></p>
  <p id="oal2"><a href="https://t.me/webfrl" target="_blank">https://t.me/webfrl</a> - веб-фриланс</p>
  <p id="JyvF"><a href="https://t.me/mtsfintechjobs" target="_blank">https://t.me/mtsfintechjobs</a> - Финтех МТС</p>
  <p id="HzTD"><a href="https://t.me/vcjob" target="_blank">https://t.me/vcjob</a> - вакансии от vc.ru</p>
  <p id="CTxS"><a href="https://t.me/cppdevjob" target="_blank">https://t.me/cppdevjob</a> и <a href="https://t.me/pydevjob" target="_blank">https://t.me/pydevjob</a></p>
  <p id="4GGL"><a href="https://t.me/naukauniver" target="_blank">https://t.me/naukauniver</a> - новости науки и ВО, вакансии</p>
  <p id="O3WU"><a href="https://t.me/studyqa" target="_blank">https://t.me/studyqa</a> - стажировки за рубежом, ещё есть <a href="https://t.me/joinchat/kQLQUGltbEtjYzQ6" target="_blank">https://t.me/joinchat/kQLQUGltbEtjYzQ6</a></p>
  <p id="9hnD"><a href="https://t.me/+Bi7qpPB6byhlODRk" target="_blank">https://t.me/+Bi7qpPB6byhlODRk</a> - &quot;Стажировки, гранты, стипендии, волонтерства и вакансии для молодых специалистов. В России и за рубежом.&quot;</p>
  <p id="NUar"><a href="https://t.me/+FnVpKeIdv55iYzQy" target="_blank">https://t.me/+FnVpKeIdv55iYzQy</a> - маркетплейс для фриланса</p>
  <p id="JhYZ"><a href="https://t.me/workcamp" target="_blank">https://t.me/workcamp</a> - работа в IT</p>
  <p id="9VjJ"><a href="https://t.me/habr_career" target="_blank">https://t.me/habr_career</a> - вакансии от Хабра</p>
  <p id="v3bV"><a href="https://fut.ru/catalog/" target="_blank">https://fut.ru/catalog/</a> - стажировки и лидерские программы</p>
  <p id="ckO7"><a href="https://jobby.ai/student_jobsearch" target="_blank">https://jobby.ai/student_jobsearch</a> - стажировки для студентов от Jobby</p>
  <h2 id="vrqY">На закуску</h2>
  <p id="n4tt"><a href="https://www.xn--80aa3anexr8c.xn--p1ai/" target="_blank">Все хакатоны России</a></p>
  <p id="kl64"><a href="https://leader-id.ru/" target="_blank">Leader ID</a></p>
  <p id="WqvC"><a href="https://www.2035.university/" target="_blank">Университет 2035</a></p>
  <p id="zDfd"><a href="https://professionals4-0.ru/" target="_blank">Профессионалы 4.0</a></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@titoffklim/extension-writing-guide</guid><link>https://teletype.in/@titoffklim/extension-writing-guide?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim</link><comments>https://teletype.in/@titoffklim/extension-writing-guide?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim#comments</comments><dc:creator>titoffklim</dc:creator><title>Гайд по написанию расширений для Джеффа</title><pubDate>Fri, 14 Apr 2023 13:09:29 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/fd/1d/fd1df0c4-41a4-4535-96c2-058fc885d430.png"></media:content><category>Код</category><description><![CDATA[<img src="https://img2.teletype.in/files/1c/1c/1c1c1d74-7d81-4841-9027-4f0f6fffda05.png"></img>На данный момент у Джеффа есть набор примеров расширений и скриптов:]]></description><content:encoded><![CDATA[
  <p id="CJ1J">На данный момент у Джеффа есть набор примеров расширений и скриптов:</p>
  <figure id="aY55" class="m_original">
    <img src="https://img2.teletype.in/files/1c/1c/1c1c1d74-7d81-4841-9027-4f0f6fffda05.png" width="1366" />
    <figcaption>Папки с расширениями на GitHub: https://github.com/markcda/jeff/tree/master/extensions</figcaption>
  </figure>
  <p id="FIon">Чтобы написать рабочее расширение для Джеффа, нужно:</p>
  <ol id="kvBN">
    <li id="EInI">Написать код для общения расширения и Джеффа (потому что они общаются путём передачи JSON поверх обычных TCP-сокетов). Если вы пишете на Python, для вас уже <a href="https://pypi.org/project/jeff-api/" target="_blank">всё сделали</a>, для других ЯП пока ещё ничего нет.</li>
    <li id="aHu2">Написать конфигурационный файл <code>extension.j.json</code>. В минимальной комплектации он выглядит так:<br /><code>{<br />  &quot;name&quot;: &quot;some_name&quot;,<br />  &quot;title&quot;: &quot;Some title&quot;,<br />  &quot;desc&quot;: &quot;Some desc&quot;,<br />  &quot;license&quot;: &quot;Some Open-Source or some proprietary&quot;,<br />  &quot;program&quot;: &quot;/path/to/program&quot;<br />}</code><br />В папках с расширениями полно примеров.</li>
    <li id="x8Ht">Написать нужную вам логику.</li>
  </ol>
  <p id="qvA7">Общение, как было упомянуто выше, происходит за счёт обмена информацией по TCP-протоколу. Расширение добавляется через диалоговое окно Джеффа и впоследствии стартует и завершается вместе с ним. Большинство расширений использует механизм аргументов для передачи портов сокетов:<br /><code>&quot;args&quot;: [<br />    &quot;alias-maker.py&quot;,<br />    &quot;&lt;SERVER_PORT&gt;&quot;,<br />    &quot;&lt;JEFF_PORT&gt;&quot;<br />  ],<br />&quot;server_ip&quot;: &quot;&quot;,<br />&quot;server_port&quot;: 23179</code><br />В итоге вместо <code>&lt;SERVER_PORT&gt;</code> подставится 23179, указанный ниже, а вместо <code>&lt;JEFF_PORT&gt;</code> подставится порт Джеффа, который можно изменять в настройках.</p>
  <p id="e6Pt">Не все расширения обязаны иметь сервер; напротив, некоторые могут только что-то отправлять в Джеффа и ничего от него не ждать. Например, так работает <code>vosk-voice-input-daemon</code>.</p>
  <p id="9v9C">Какие возможности предоставляет Джефф для расширений?</p>
  <ol id="HKfn">
    <li id="5XYV"><em>Внутренняя память.</em><br />В Джеффе есть общее между всеми расширениями хранилище JSON-объектов.<br />Вот так выглядит запрос на получение данных: <code>{&quot;memory_cells&quot;: [&quot;needed_memory_cell_1&quot;, &quot;needed_2&quot;, &quot;needed_3_etc&quot;]}</code><br />- и на сохранение: <code>{&quot;store_in_memory&quot;: {&quot;some_key&quot;: &quot;some value, even decimal, double, boolean, object or array&quot;}}</code>.<br />Причём по умолчанию каждый запуск три ячейки - <code>jeff-lang, jeff-os, jeff-bundle-dir</code> заполняются Джеффом.</li>
    <li id="yy0v"><em>Получение сообщений.</em><br />Если вы указали в файле конфигурации расширения, что у него есть сервер, это значит, что Джефф будет вам отправлять сообщения пользователя каждый раз, когда сам не сможет на них ответить. Если вы хотите всегда передавать ввод пользователя в расширение, добавьте в конфигурацию строчку <code>&quot;always_send&quot;: true</code>.</li>
    <li id="Yny6"><em>Отправка сообщений.</em><br />Вот примеры JSON запросов на отправку:<br /><code>{&quot;send&quot;: &quot;какое-то сообщение на отправку&quot;}<br />{&quot;send_as_user&quot;: &quot;сообщение на отправку от лица пользователя&quot;}<br />{&quot;send_info&quot;: &quot;информация от расширения&quot;}<br />{&quot;send_warning&quot;: &quot;предупреждение&quot;}<br />{&quot;send_status&quot;: {&quot;id&quot;: &quot;уникальный идентификатор обновляемого сообщения&quot;, &quot;msg&quot;: &quot;сообщение, которое может меняться со временем&quot;}}</code></li>
    <li id="Xmbp"><em>Добавление выражений в базу данных.</em><br />Делается это так:<br /><code>{&quot;add_expr&quot;: [<br />  {<br />    &quot;activator_text&quot;: &quot;пользовательский ввод&quot;,<br />    &quot;reagent_text&quot;: &quot;ответ Джеффа&quot;,<br />    &quot;properties&quot;: {&quot;какие-то свойства&quot;: &quot;их значения&quot;,..},<br />    &quot;exec&quot;: false | true<br />  },..<br />]}</code></li>
    <li id="xagx"><em>Эксклюзивное общение по сценарию.</em><br />В сущности, <a href="https://github.com/markcda/jeff/tree/master#scenarios" target="_blank">сценарий</a> представляет из себя способ взаимодействия, когда весь ввод пользователя без обработки перенаправляется в одно расширение. Джефф в этом смысле работает как паром.</li>
  </ol>
  <p id="ZgPn">Если у вас есть идеи расширений, или вы уже написали расширение и хотите им поделиться, <a href="https://t.me/titoffklim" target="_blank">пишите</a>!</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@titoffklim/night-fary-tale</guid><link>https://teletype.in/@titoffklim/night-fary-tale?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim</link><comments>https://teletype.in/@titoffklim/night-fary-tale?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim#comments</comments><dc:creator>titoffklim</dc:creator><title>Ночная сказка</title><pubDate>Tue, 11 Apr 2023 23:19:21 GMT</pubDate><media:content medium="image" url="https://img4.teletype.in/files/fe/74/fe74f96b-e3b7-458c-a25d-07525a4bf6c3.png"></media:content><category>Рассказы</category><description><![CDATA[Дорогое дитя, я пишу тебе сквозь года. Мне всегда хотелось узнать, есть ли у человека предназначение, создан он для чего-то или предназначен самому себе, подчинён своею волею или божественным посягательством.]]></description><content:encoded><![CDATA[
  <p id="830x">Дорогое дитя, я пишу тебе сквозь года. Мне всегда хотелось узнать, есть ли у человека предназначение, создан он для чего-то или предназначен самому себе, подчинён своею волею или божественным посягательством.</p>
  <p id="jFnh">У меня пусто в душе. Я не так часто вижу свет в конце тоннеля, как хотелось бы. Внешне я энергичен и искусен, но сладкие яства жития не укрепляют мои ноги. Возможно, тебе предстоит ответить на самый главный вопрос в твоей жизни - зачем тебе всё это?</p>
  <p id="Pvk7">Когда я соотносил собственное существование со Вселенной и её обитателями, я думал об утилитаризме, гедонизме. В определённый момент я изобрёл для себя сказку о консеквенциализме с критерием расширения свободы действий, в рамках которой показал математически и логически разрешение гильотины Юма, исходя из научной теории о происхождении человека: человек должен иметь свободу, но необязательно ей пользоваться.</p>
  <p id="fNYR">И что мне это дало? Я создавал свободу, вполне свободно ей пользовался. И во благо себе, и во вред, - всяко умеренно. Но изнутри меня глодало чувство, что я пытаюсь себе доказать что-то. Я пишу книги и рассказы, программы и песни, дневники и планы, строю своё будущее и искренне верю в хорошее. Я верю в людей и капитализм, правда, не в тот, что существует в искажённом понимании политиков. Разве ограничение свободы других по причине явления личности некоей абсолютной истины истинно само по себе?</p>
  <p id="xqjU">Я боюсь, что, даже определяя то, что для меня правильно и что нет, ошибаюсь. Меня каждый раз вытаскивают из этого разные люди, которым я очень благодарен. Я боюсь одиночества, понимая, что из-за своих знаний и внешней необходимости внутренне никому точно не буду нужен.</p>
  <p id="Ss6F">Дитя, не знаю, какую сказку тебе рассказать, чтобы было чему научиться в ней. Не знаю, что есть жизнь и как человек провернул гигантский скачок в эволюции, естественной и социальной. Не знаю, докажем ли мы гипотезу Римана и найдём ли супериорный алгоритм шифрования. Не знаю даже, обоснована ли наука и вера в неё, или же она неотличима от религии. Не знаю, по какому праву глубоко религиозные люди считают атеистов аморальными, и не знаю, как жить атеисту, когда у религиозных есть совершенная вера.</p>
  <p id="JqkQ">Но каждое утро рано встаю, хоть и боюсь, что этот автоматизм уже не скрывается. Занимаюсь физически и умственно, хоть и боюсь, что не тем. Трачу себя, хоть и боюсь, что не на то и не на тех.</p>
  <p id="5E0u">Иногда мне хочется плакать от тягот, которые невозможно выразить кардиналом натурального или даже действительного множеств и при этом невозможно описать в реальности существующими тяготами.</p>
  <p id="2ne4">Но всё-таки что-то я узнал вчера ночью. Это твой урок, милое дитя.</p>
  <p id="GQ3b">Вселенная тоже пуста. Но быть живой ей это не мешает.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@titoffklim/features-of-modern-tech-in-tcs-is</guid><link>https://teletype.in/@titoffklim/features-of-modern-tech-in-tcs-is?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim</link><comments>https://teletype.in/@titoffklim/features-of-modern-tech-in-tcs-is?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim#comments</comments><dc:creator>titoffklim</dc:creator><title>Особенности обеспечения информационной безопасности в области телекоммуникационных систем в настоящее время</title><pubDate>Sat, 04 Feb 2023 19:28:56 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/e5/25/e525ce85-cfcb-4f18-9af0-61001dba1705.png"></media:content><category>Код</category><description><![CDATA[Если вкратце — технологии постоянно меняются. Если раньше мы использовали для защиты узкие утилиты, выполняющие одну-две задачи, совсем недавно — комплексные антивирусы и программы для защиты инфраструктуры, то сейчас для полноценной защиты используются ячеистые архитектуры кибербезопасности вкупе с сервисами по защите от сетевых рисков, под капотом у которых — нейронные сети. И это только часть того, чем живёт современная информационная безопасность. Ваш покорный слуга проанализировал отчёты SOC Prime, SANS Cloud Security, Mandiant и Gartner за последние два года, чтобы составить портрет современной архитектуры информационной безопасности на предприятии и в программных продуктах, а также её скорого будущего.]]></description><content:encoded><![CDATA[
  <section style="background-color:hsl(hsl(34,  84%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="V5tV">Если вкратце — технологии постоянно меняются. Если раньше мы использовали для защиты узкие утилиты, выполняющие одну-две задачи, совсем недавно — комплексные антивирусы и программы для защиты инфраструктуры, то сейчас для полноценной защиты используются ячеистые архитектуры кибербезопасности вкупе с сервисами по защите от сетевых рисков, под капотом у которых — нейронные сети. И это только часть того, чем живёт современная информационная безопасность. Ваш покорный слуга проанализировал отчёты SOC Prime, SANS Cloud Security, Mandiant и Gartner за последние два года, чтобы составить портрет современной архитектуры информационной безопасности на предприятии и в программных продуктах, а также её скорого будущего.</p>
  </section>
  <p id="0vzq">Для того, чтобы иметь возможность пользоваться различными аналогами средств ОИБ и позволять им консолидировать источники информации для принятия оперативных решений, люди придумали ячеистые архитектуры кибербезопасности — <strong>CSMA</strong>. CSMA имеет четыре основных уровня:</p>
  <ol id="7nqy">
    <li id="BawT">Аналитика безопасности и интеллект.</li>
    <li id="M9L3">Сводные информационные панели.</li>
    <li id="gMzD">Распределённая идентификационная ткань.</li>
    <li id="WXdq">Консолидированные политика и управление доступом.</li>
  </ol>
  <p id="zSZb">Чтобы поддерживать CSMA, разработчики средств ОИБ повсеместно внедряют в свои продукты открытые стандарты и общие API для поддержки интеграции сторонних поставщиков.</p>
  <p id="9jje">Сервисы по защите от сетевых рисков и их составные элементы — решения по управлению внешней поверхностью атаки и атаки киберактивов — предназначены для анализа внешних и внутренних компонентов локальной сети вашей организации и их мониторинга в режиме реального времени. Многие системы <strong>DRPS</strong> обогащены возможностями Threat Intelligence, но в основном предназначены для проактивных действий по выявлению и блокировке внешних угроз. Но <strong>CAASM</strong> предназначены для анализа локальной сети и всех устройств в нём, в то время как <strong>EASM</strong>-системы зачастую являются системами защиты бренда — Brand Protection — и анализируют мошеннические сайты при помощи разведки по открытым источникам (OSINT) с целью обнаружения относящихся к организации данных. Современные CAASM- и EASM-системы используют машинное обучение для выявления угроз. Наиболее популярными DRPS-продуктами во всём мире являются BlueVoyant Sky: DRP, CybelAngel ERPP, Digital Shadows SearchLight; в России — BI.ZONE Brand Protection, Group-IB Digital Risk Protection, Infosecurity ETHIC и Kaspersky Threat Intelligence.</p>
  <p id="L0gK">Технологии управления идентификацией и доступом предназначены для защиты данных путём реализации политик доступа к сведениям. Благодаря идентификации пользователей мы можем понимать, какие сведения им можно передавать и раскрывать, а какие — нельзя. Помимо применения к пользователям <strong>IAM</strong> используются для идентификации промежуточных сервисов. К самым известным продуктам относятся такие программные продукты, как SELinux (подсистема Linux, начиная с версии 2.6), Secret Net, Sber Platform V; помимо них, существуют ещё и аппаратные средства, такие, как «<strong>Соболь</strong>» Кода Безопасности. К облачным продуктам и интерфейсам для конечных пользователей относят такие составляющие IAM, как многофакторную аутентификацию, аутентификацию на основе сертификатов и сторонние сервисы аутентификации (например, Google или Microsoft OAuth). А поскольку такие системы часто подвергаются атакам как чуть ли не единственные барьеры на пути к данным и управлению КИИ, для выявления атак на IAM и оперативного реагирования на инциденты существуют инструменты для распознавания и реагирования на угрозы идентификации — <strong>ITDR</strong>. Многие продукты IAM по умолчанию включают в себя инструментарий ITDR.</p>
  <p id="1xZJ">Системы аудита, отслеживания и защиты данных необходимы, в свою очередь, для разграничения данных, равно как и IAM; фундаментальное различие между ними заключается в контентном разграничении доступа, а не в файловом. Также <strong>DCAP</strong>-системы позволяют анализировать данные и организовывать хранение информации и доступ к ней максимально эффективно и безопасно. Аналитики прогнозируют в будущем поглощение DCAP-системами <strong>DLP</strong> и повсеместное использование из-за ужесточения контроля за персональными данными со стороны регулятора. DLP же, как системы контроля каналов передачи данных, ищут и категоризируют критичную информацию, предотвращая её перемещение и передачу за пределы периметра корпоративного контура безопасности. К системам DLP относят <strong>DAM</strong>, системы мониторинга активности баз данных.</p>
  <p id="VamT">Системы выявления событий ИБ в реальном времени позволяют распознать потенциальные угрозы безопасности и уязвимости до того, как они станут способны нанести удар бизнесу. Такие системы покрывают аномалии в поведении пользователя, используя для этого машинное обучение. Самые популярные системы <strong>SIEM</strong> в России — это Ankey SIEM, Kaspersky Unified Monitoring and Analysis Platform и KOMRAD Enterprise SIEM.</p>
  <p id="jks3">Системы кибербезопасности для облачных приложений объединяют SIEM, DCAP/DLP и IAM для обеспечения кибербезопасности по отношению к важным данным, располагаемым не в корпоративной сети организации, а в сети облачного провайдера. Такие системы, как правило, унитарны и совмещают в себя множество продуктов. Самый известный пример — Microsoft Cloud Security Solutions. Зачастую такие системы сочетаются с защитой от DDoS-атак, позволяя фильтровать подозрительные запросы к серверам.</p>
  <p id="tmch">Существуют также и комплексные решения для организации безопасности, автоматизации и реагирования, предназначаемые для сбора информации о событиях информационной безопасности и автоматизации типовых сценариев реагирования на них, избавляя специалистов ИБ от необходимости управлять каждым из защитных решений в отдельности и помогая им сфокусироваться на анализе сложных инцидентов. Ключевое отличие <strong>SOAR</strong> от SIEM в этом ключе заключается в том, что SOAR рассчитаны именно на на автоматизацию. Самые популярные системы иностранных разработчиков — IBM Resilient SOAR, Cortex XSOAR и Cisco SecureX, российских — R-Vision IRP.</p>
  <p id="PHun">Для анализа сложных инцидентов зачастую своих специалистов бывает недостаточно, поэтому очень часто компании обращаются к сервисам <strong>EaaS</strong>, предоставляющим стороннюю профессиональную экспертизу инцидентов ИБ.</p>
  <p id="Q4D9">Для превентивного исправления уязвимостей существует целая отрасль кибербезопасности, называемая Threat Intelligence — <strong>TI</strong>. Дистрибутив Linux «Ubuntu» позволяет исправлять уязвимости в ядре без перезагрузки системы (Ubuntu Livepatch Service), а <strong>CTSE</strong> позволяет организовывать поиск по имеющимся уязвимостям (обычно им присваиваются номера в координатах CVE).</p>
  <section style="background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="gzIv">Давайте рассмотрим типовые задачи защиты информации, связанные с компьютерными сетями:</p>
    <ol id="vKcR">
      <li id="fiCr">Защита облачных приложений.</li>
      <li id="zAf7">Контроль каналов передачи данных.</li>
      <li id="A22A">Контроль удалённого доступа и идентификации.</li>
      <li id="A2vc">Защита корпоративного контура от внешних угроз.</li>
    </ol>
    <p id="2oOM">Обеспечение безопасности облачных приложений ложится на CASB-системы, предоставляемые облачными провайдерами. Широко используются Anti-DDoS-сервисы, например, от Cloudflare. Контроль каналов передачи данных осуществляется DLP-системами, доступ и идентификация должны подразумевать использование IAM и MFA/CBA, а защита корпоративного контура - это задача для CAASM-систем. Таким образом, <strong>современные технологии обеспечения информационной безопасности компьютерных сетей предполагают консолидированную и ячеистую архитектуру, сочетающую принцип нулевого доверия и возможность безопасного удалённого доступа при помощи продвинутых технологий аутентификации, контроля каналов передачи данных и защиты от разрушения корпоративной экосистемы изнутри и извне.</strong></p>
  </section>
  <p id="KnK8">При этом для реальной защиты БТКС сами сервисы и технологии, использующие телекоммуникационные технологии, должны предполагать наличие защитных механизмов, которые следует закладывать на этапе их проектирования.</p>
  <p id="NkcB">Например, для разработки облачного программного продукта команда программистов должна обладать минимальными навыками обеспечения защиты информации, используя:</p>
  <ol id="o5G7">
    <li id="xSJe">Хэширование вместо прямой передачи данных аутентификации</li>
    <li id="UPVE">Хранение токенов и иной критической информации в защищённых местах, таких, как аппаратные доверенные хранилища или удалённые облачные сервисы.</li>
    <li id="YtVN">Защиту от случайных или намеренно испорченных вводимых данных путём проверки всей внешней информации.</li>
    <li id="Hq2B">Безопасное управление внутренней памятью программы.</li>
    <li id="rw1o">Постоянное сканирование на уязвимости исходного кода при помощи специальных инструментов и статических анализаторов.</li>
    <li id="mkjp">Систему внедрения исправлений.</li>
    <li id="sxF5">Систему поиска уязвимостей в базах данных и реагирования на инциденты.</li>
    <li id="uXHT">Современные стандарты шифрования данных.</li>
  </ol>
  <p id="3W1X">Помимо программных средств защиты компьютерных сетей, существуют современные технологии аппаратной защиты компьютерных и телефонных сетей. Основным направлением исследований в последнем десятилетии стали квантовые сети, передача данных в которых осуществляется фотонами, что подразумевает физическую невозможность перехвата данных.</p>
  <p id="vohA">При этом развивается сфера квантовых вычислений, позволяющих добиться расшифровки передаваемых по HTTPS-соединениям сообщений путём использования квантовых компьютеров. Например, китайские исследователи сообщили об успешном взломе RSA: это будет означать возможность расшифровки сообщений за фиксированное небольшое время для стандартных алгоритмов шифрования, основанных на простых числах.</p>
  <p id="ifNm">В то же время исследователи уже предлагают специализированные стандарты шифрования, которые будут устойчивы к расшифровке сообщений квантовыми компьютерами. В них используются ключи до 3072 бит длиной и совершенно другие алгоритмы, для которых не существует на данный момент контралгоритмов для квантовых компьютеров. Но этот момент — очень условный, и поэтому <strong>сфера информационной безопасности — самая динамично развивающаяся сфера на стыке IT и точных наук, требующая от специалистов этой сферы постоянного развития своих компетенций.</strong></p>
  <p id="9G5u">Помимо защиты от раскрытия информации, зачастую необходимо обеспечивать неизменяемость определённой информации, такой, как истории банковских транзакций и т. п. Для этих целей разрабатываются системы, применяющие в своей работе технологию блокчейна, и децентрализованные сервисы, которые в ближайшем будущем станут стандартом нового Интернета — Web3.</p>
  <p id="XCL8">Таким образом, правильно сочетая общепринятые стандарты в области ОИБ, требования регуляторов и современные технологии ОИБ, можно добиться беспрецедентного уровня информационной безопасности, основанной на физических принципах и интеллектуальном подходе.</p>
  <p id="yiDX"><em>Литература:</em></p>
  <ol id="fWw0">
    <li id="gOQR">Бондарев В. В. Введение в информационную безопасность автоматизированных систем [Текст] / В.В. Бондарев // М.: МГТУ им. Н. Э. Баумана — 2014.</li>
    <li id="2WA2">Бёрд Д. DevOpsSec [Текст] / Джим Бёрд // O’Reilly — 2016.</li>
    <li id="FqF1">Информационная безопасность телекоммуникационных систем: <a href="https://searchinform.ru/informatsionnaya-bezopasnost-telekommunikatsionnykh-sistem/" target="_blank">https://searchinform.ru/informatsionnaya-bezopasnost-telekommunikatsionnykh-sistem/</a></li>
    <li id="99sV">Информационная безопасность: руководство по защите от внутренних угроз. Комплексная защита данных – СёрчИнформ, 2022 (<a href="http://www.searchinform.ru" target="_blank">www.searchinform.ru</a>).</li>
    <li id="weta">Основные сценарии реализации угроз на АСУ ТП и их преломление на методику оценки угроз ФСТЭК – Алексей Лукацкий, Cisco Secure, 2021.</li>
    <li id="k2AQ">ПАК «Соболь». Код Безопасности: <a href="https://securitycode.ru/products/pak_sobol/" target="_blank">https://securitycode.ru/products/pak_sobol/</a></li>
    <li id="y2zb">Семь трендов информационной безопасности 2022: <a href="https://www.cnews.ru/reviews/security2022/articles/sem_trendov_informatsionnoj_bezopasnosti" target="_blank">https://www.cnews.ru/reviews/security2022/articles/sem_trendov_informatsionnoj_bezopasnosti</a></li>
    <li id="BPRF">Технология блокчейн: что надо знать в 11 карточках: <a href="https://trends.rbc.ru/trends/industry/5f05c0a79a7947aac5c7577a" target="_blank">https://trends.rbc.ru/trends/industry/5f05c0a79a7947aac5c7577a</a></li>
    <li id="SfOr">Физики реализовали масштабируемую сеть квантовой коммуникации: <a href="https://nplus1.ru/news/2020/09/03/8-user-quantum-communication-network" target="_blank">https://nplus1.ru/news/2020/09/03/8-user-quantum-communication-network</a> </li>
    <li id="qXWK">At a glance: PCI DSS v4.0 – PCI Security Standards Council LLC, 2022.</li>
    <li id="z3TQ">CSMA is more than XDR: An introducion to cybersecurity mesh architecture: <a href="https://coffee-web.ru/blog/csma-is-more-than-xdr-an-introducion-to-cybersecurity-mesh-architecture/" target="_blank">https://coffee-web.ru/blog/csma-is-more-than-xdr-an-introducion-to-cybersecurity-mesh-architecture/</a></li>
    <li id="HCGv">Detection as Code Innovation Report 2021: The Power of Collaborative Cyber Defence – SOC Prime, 2021 (<a href="http://www.socprime.com" target="_blank">www.socprime.com</a>).</li>
    <li id="27ie">Hype Cycle for Security Operations – Gartner, 2022.</li>
    <li id="A8qD">MITRE ATT&amp;CK: <a href="https://attack.mitre.org/" target="_blank">https://attack.mitre.org/</a></li>
    <li id="iBja">Market Guide for Security Orchestration, Automation and Response Solutions – Gartner, 2022.</li>
    <li id="Svnp">Nine Key Cloud Security Concentrations &amp; Securing Web Application Technologies Checklist – SANS Cloud Security, 2022 (<a href="http://www.sans.org/cloud-security" target="_blank">www.sans.org/cloud-security</a>).</li>
    <li id="765Y">Special Report: M-TRENDS 2022 – Mandiant, 2022 (<a href="http://www.mandiant.com" target="_blank">www.mandiant.com</a>).</li>
    <li id="Btev">What ITD and ITDR means in a Zero-Trust world? <a href="https://venturebeat.com/security/what-identity-threat-detection-and-response-itdr-means-in-a-zero-trust-world/" target="_blank">https://venturebeat.com/security/what-identity-threat-detection-and-response-itdr-means-in-a-zero-trust-world/</a> </li>
    <li id="aCLE">What is SIEM? <a href="https://ibm.com/topics/siem" target="_blank">https://ibm.com/topics/siem</a></li>
  </ol>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@titoffklim/machine-learning-av-guarantee</guid><link>https://teletype.in/@titoffklim/machine-learning-av-guarantee?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim</link><comments>https://teletype.in/@titoffklim/machine-learning-av-guarantee?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim#comments</comments><dc:creator>titoffklim</dc:creator><title>Машинное обучение как гарантия кибербезопасности</title><pubDate>Thu, 29 Sep 2022 09:20:39 GMT</pubDate><description><![CDATA[На текущий момент основная угроза информационной безопасности любого персонального компьютера исходит от двух факторов: использования непроверенного программного обеспечения и человеческих ошибок, связанных с этим. Между тем, защита ПК также критически важна, как и защита корпоративных и государственных систем. Человеческий фактор играет здесь не последнюю роль: часто происходит так, что в организациях со слабо развитой культурой информационной безопасности сотрудники берут с работы важные документы, чтобы продолжить работу над ними в домашних условиях, то есть на не аттестованных для сведений, составляющих коммерческую или государственную тайну, компьютерах. Это не говоря уже о том, что личные финансовые, конфиденциальные данные, в том...]]></description><content:encoded><![CDATA[
  <h2 id="4hxA">В чем состоит проблема?</h2>
  <p id="tkvj">На текущий момент основная угроза информационной безопасности любого персонального компьютера исходит от двух факторов: использования непроверенного программного обеспечения и человеческих ошибок, связанных с этим. Между тем, защита ПК также критически важна, как и защита корпоративных и государственных систем. Человеческий фактор играет здесь не последнюю роль: часто происходит так, что в организациях со слабо развитой культурой информационной безопасности сотрудники берут с работы важные документы, чтобы продолжить работу над ними в домашних условиях, то есть на не аттестованных для сведений, составляющих коммерческую или государственную тайну, компьютерах. Это не говоря уже о том, что личные финансовые, конфиденциальные данные, в том числе пароли, точно так же остаются беззащитны перед похищением, уничтожением или шифровальщиками. Программные же угрозы постоянно мимикрируют под ПО, знакомое для пользователя, в связи с чем практически невозможно его отличить даже опытным пользователям и специалистам, а антивирусные базы, создаваемые по сигнатурам уже известных угроз, бессильны перед неизвестными. В том числе не исключен вид угроз, когда в очередном обновлении проверенного ПО привносится код, который в итоге выполняет несанкционированные действия.</p>
  <p id="gjfN">Как мы можем в таком изменчивом мире обеспечить безопасность рядовому пользователю? Если за компьютер посадить специалиста по информационной безопасности, он будет способен эксплуатировать его с соблюдением требований ИБ, но к обычному человеку не предъявляются требования, какие обычно предъявляют к подобного рода специалистам.</p>
  <h3 id="PjCv">Характеристики средства обеспечения ИБ</h3>
  <p id="bp04">Чтобы решить проблему, нужно создать программный комплекс, который будет способен отслеживать все виды угроз, способных причинить вред информации и/или их владельцу. Такой комплекс должен обладать следующими свойствами:</p>
  <ul id="RBQY">
    <li id="kHFG">гибкость - способность реагировать на широкий круг угроз</li>
    <li id="VkI2">скорость - способность за короткое время определять угрозы</li>
    <li id="QTBw">точность - способность гарантировать безопасность.</li>
  </ul>
  <p id="xaNu">Такую задачу решить под силу только машинному обучению в виде нейросетей.</p>
  <h3 id="ftrZ">Почему нейронным сетям можно доверять столь сложную и важную задачу?</h3>
  <p id="8dh4">Машинное обучение доказало свою состоятельность на ряде задач. Например, автопилоты Tesla и Яндекса позволяют ездить на автомобилях без водителей; нейросеть Google NMT сделала их сервис перевода соотносимым по качеству с человеческим переводом; машинное зрение позволяет определять по кадрам Google Street View названия улиц, магазинов и других мест; в медицине Adversarial Auto Encoder помог найти 69 молекул, половина из которых используется в борьбе с раком; FGSM позволяет противостоять распознаванию лиц в Интернете путем добавления невидимых для человеческого глаза пикселей.</p>
  <p id="aO3S">В совокупности этих успехов и заключается готовность машинного обучения к серьезным задачам, в том числе с рисками для жизни и здоровья людей.</p>
  <h3 id="nRiH">Почему классические антивирусы не будут так эффективны?</h3>
  <p id="pzUf">Пассивный анализ в основном базируется на вычислении хэш-сумм от файлов. Минус такого подхода заключается в том, что значения хэшей двух файлов, различающихся хотя бы одним байтом данных, различаются до неузнаваемости. Грубо говоря, создатель вируса может буквально штамповать вредоносные копии программ, которые не будут находиться в базе данных антивирусов.</p>
  <p id="m6MP">Активный же анализ основывается на нескольких важных компонентах, например, системе разграничения прав пользователей (AppArmor, SELinux) и др. Но такой вид анализа требует настройки специалистом, а не рядовым пользователем. Более того, пользователи зачастую сами виновны в том, что буквально отдают в руки злоумышленникам важную информацию. Но это не значит, что мы не должны из-за этого её защищать.</p>
  <h3 id="H9kE">Как модель машинного обеспечения может гарантировать информационную безопасность?</h3>
  <p id="OUVH">Несмотря на обилие угроз и постоянно растущее число вирусов, существует их емкая классификация, и, более того, у зловредных программ есть ограниченное количество эндпойнтов - точек, через которые они могут получить доступ к определенным устройствам и сведениям. Причина этому кроется в том, что мы определяем &quot;зловредность&quot; программ по их поведению, связанному с такими эндпойнтами, и раз их в любой системе ограниченное число, следовательно, можно построить модель, которая сможет анализировать поведение программ и блокировать деструктивные паттерны.</p>
  <p id="NLdY">При этом надо понимать, что гарантия - это в любом случае определённая вероятность. Успешность стратегий защиты информации в основе своей определяется долей вероятности, что атаки будут безуспешны. Если такая вероятность достигнет 95%-99%, мы будем считать, что наша модель выполняет обозначенные функции.</p>
  <h3 id="uQPF">Классификация программных угроз</h3>
  <p id="wIIb">Угрозы могут быть доставлены на компьютер следующими способами:</p>
  <ol id="8yVJ">
    <li id="jiPH">В виде скомпилированной для конкретной платформы и ОС программы, представленной бинарным кодом, где есть конкретные строки и обращения к известным системным библиотекам и ядру, способные нанести вред.</li>
    <li id="Vi2n">В виде скомпилированной программы, способной выполнять небезопасные паттерны, определяемые интерпретируемым кодом, данными из Сети и/или пользовательским поведением.</li>
    <li id="zuMw">В виде программы, которая выполняет внешне безопасные команды, но основана на знании злоумышленниками уязвимостей ОС и прикладных программ и библиотек.</li>
  </ol>
  <h3 id="xUOb">Анализ статических программ (п. 1)</h3>
  <p id="NSH5">Есть два способа проверить статические программы на наличие угроз: проанализировать код, представленный в скомпилированном варианте - и сэмулировать выполнение данной программы.</p>
  <p id="Li7M">Анализ бинарного кода, направленный на выявление небезопасных паттернов, может иметь невысокую эффективность по разным причинам; например, программный код могли обфусцировать, чтобы паттерны невозможно было выявить. В то же время ни анализ бинарного кода, ни эмуляция выполнения программы не могут предусмотреть все возможные ветвления программы, и, следовательно, не могут найти ни искомых паттернов, ни - во втором случае - даже завершить эмуляцию программы.</p>
  <p id="8qvc">Отсюда следует, что анализ статических программ малоэффективен, если их разработчики применяют способы защиты исходного кода - целенаправленно для обхода антивирусного ПО или же с целью защиты интеллектуальной собственности.</p>
  <h3 id="whwY">Анализ динамических программ (п. 2)</h3>
  <p id="uKfj">Анализ динамических программ усложняет предыдущую задачу тем, что теперь угроза может исходить не непосредственно от программы, а от третьих лиц, например, пользователя программы или создателей контента, который приходит из Сети. Помимо этого, и в обычных программах присутствуют паттерны, потенциально способные нанести вред информации или её владельцам, но дело в том, как именно они выполняются. И авторы вредоносных программ иногда не включают вредоносный код в саму скомпилированную программу, а внедряют её с помощью скрипта - или же вовсе пишут вредоносные скрипты. Проблема здесь заключается в том, что скрипты могут быть написаны на разных языках, и не на все языки можно запрограммировать анализатор, выполняющий поиск угроз.</p>
  <h3 id="gWCn">Анализ программ, использующих уязвимости системы (п. 3)</h3>
  <p id="NsPH">Анализ таких программ и вовсе усложняется благодаря тому, что они вообще не выполняют внешне вредоносных действий: их осуществляют прикладные и системные программы, которые считаются безопасными по умолчанию или же не могут быть безопасными по определению и поэтому игнорируются.</p>
  <p id="FhcU">Дело в том, что ядро операционной системы должно для нормального функционирования обладать всеми возможностями, в том числе составляющими небезопасные паттерны. Но, опять-таки, использование таких возможностей в определённой последовательности и приводит к нарушению ИБ. Например, только за 2019 год Red Hat исправил более 1000 CVE в своём дистрибутиве RHEL, согласно их отчёту Product Security Risk Report.</p>
  <p id="qMi1">Большинство системных программ используют прямые вызовы ядра и системных библиотек для взаимодействия с сетевыми и физическими устройствами. Для защиты от уязвимостей разные ОС используют разные средства, например, в Android версии 11 и выше используют разрешения приложений (так как все приложения для этой ОС пишутся на Java и Kotlin и выполняются при помощи виртуальных машин Dalvik и ART), чтобы ограничивать доступ приложений к тем функциям, к которым они не должны иметь доступа. В то же время Windows не имеет такого механизма (у Windows-программ нет манифеста, в котором декларировались бы разрешения, требуемые разработчиками для обеспечения работоспособности программы). Более того, даже декларирование разрешений не защищает конечного пользователя после того, как он предоставил вредоносному приложению требуемые разрешения. А в самой ОС Android не запрашиваются разрешения для получения фингерпринта устройства, которое позволило бы практически однозначно определить конкретное физическое устройство, и передачи его по Интернету третьим лицам в целях слежения.</p>
  <p id="xaP2">Более того, самый уязвимый элемент информационной безопасности - это зачастую сам пользователь компьютера, и его действия могут вследствие незнания или иных причин нанести гораздо больший вред, чем эксплуатация уязвимостей программных систем. Большинство атак за первые три квартала 2022 года были успешно осуществлены именно при помощи навыков социальной инженерии.</p>
  <h3 id="b3jS">Анализ реального времени (RTA)</h3>
  <p id="KtOr">Как мы выяснили, для того, чтобы обеспечить защиту от угроз, недостаточно применять пассивный анализ. Гораздо важнее поставить акцент на активном анализе, так как в этом случае:</p>
  <ol id="7mHV">
    <li id="5K7Z">Мы можем блокировать выполнение деструктивной части программы, при этом задействуя её безопасную часть.</li>
    <li id="4tT0">Проблемы с ветвлением бинарного кода и пользовательским вводом решаются прямо в тот момент, когда приходит следующая команда на процессор, потому что к этому моменту все необходимые данные программы имеются.</li>
  </ol>
  <p id="f2lo">Таким образом, активный анализ - RTA - позволяет нам эффективно противостоять угрозам в статических и динамических программах, не использующих уязвимости системы. В следующем же разделе мы рассмотрим проблемы, связанные с этими уязвимостями.</p>
  <h2 id="RIx0">Создание комплекса защиты информации</h2>
  <p id="jC31">Продукт, способный обеспечивать его пользователям надёжный уровень кибербезопасности, должен решать проблему оценки вероятности. Поскольку проектировать планируется именно продукт, производящий RTA, вероятность будет означать <em>безопасность выполнения предложенной команды</em>.</p>
  <p id="F7v4">Что немаловажно, видов и типов угроз бесчисленное множество, хотя они и совершаются в ограниченном пространстве на ограниченном числе физических устройств одного компьютера. Например, в начале 2022 года один специалист смог передавать данные с компьютера, изменяя скорость вращения кулера и фиксируя итоговую вибрацию на диктофон. Это не говоря уже о том, что двумя годами ранее хакеры научились определять нажимаемые на клавиатуре клавиши благодаря характерному звуку нажатия.</p>
  <p id="sPhv">Но даже такие сложные и, казалось бы, непредсказуемые атаки можно предотвратить, если понять, что лежит в основе паттернов поведения таких программ.</p>
  <h3 id="o4o8">Как оценить успехи нашей ML-модели?</h3>
  <p id="7H09">Одним из ключевых факторов оценки работоспособности модели машинного обучения является точность модели. При этом второй ключевой фактор - это переобученность. Как правило, обучение на наборе данных строится путем разделения набора на маленькую обучающую выборку и остальную, тестовую выборку. Если точность на обучающей выборке гораздо больше, чем на тестовой, это позволяет судить о том, что модель переобучена, т.е. попросту запомнила обучающую выборку, а вовсе не выявила правила, по которым она классифицируется. В процессе обучения модели мы должны стремиться:</p>
  <ol id="Pvjy">
    <li id="lPs8">Набрать большой набор данных (чем больше - тем лучше).</li>
    <li id="7C1P">Оптимально разделить набор на выборки.</li>
    <li id="zE1i">Следить за тем, чтобы точность модели увеличивалась, а переобученность - уменьшалась.</li>
  </ol>
  <h3 id="K1v6">Архитектура комплекса защиты информации</h3>
  <p id="vuqB">Комплекс ЗИ должен состоять как минимум из двух компонентов:</p>
  <ol id="pwUR">
    <li id="m0g3"><em>Пассивный анализатор</em> - собирает данные о программе перед её запуском.</li>
    <li id="ypwZ"><em>RTA-модель</em> - программа, принимающая на вход данные с пассивного анализатора и оценивающая действия, затрагивающие информационную безопасность в реальном времени.</li>
  </ol>
  <h3 id="fQRt">Архитектура ML-модели</h3>
  <p id="5T5r">Предлагается разработать рекуррентную нейронную сеть, состоящую из двух ступеней:</p>
  <ol id="Zqzv">
    <li id="mIV6">Входные данные - категории совершаемых / возможно совершаемых операций; преднамеренная классификация приложения (пользователем, системным администратором или поставщиком). Выходные данные - вероятностная классификация приложения.</li>
    <li id="ZOlm">Входные данные - вероятностная классификация приложения, полученная на первом этапе; рекуррентная оценка вероятности угрозы со стороны приложения; следующее по очереди выполнения действие, затрагивающее информационную безопасноть. Выходные данные - оценка вероятности угрозы со стороны приложения.</li>
  </ol>
  <p id="luPj">Первая ступень нейронной сети срабатывает перед запуском процесса. Мы узнаём, что вообще делает приложение и зачем оно нужно. Входные данные - <code>n</code> булевых значений и <code>m</code> вероятностных значений, где <code>n</code> - число категорий совершаемых операций, затраивающих информационную безопасность, <code>m</code> - число установленных категорий в классификации приложений. Выходные данные - <code>m</code> вероятностных значений.</p>
  <p id="vvlr">Вторая ступень нейронной сети встраивается между процессом и операционной системой, постоянно анализируя действия программы. Входные данные - <code>m + k + 1</code> вероятностных значений и одно числовое значение, где <code>m</code> - число установленных категорий в классификации приложений; <code>k</code> - набор чисел, служащих буфером для запоминания предшествующих команд; одно вероятностное значение - оценка вероятности угрозы, одно числовое значение - код следующей команды. Выходные данные - <code>k + 1</code> вероятностных значений, где <code>k</code> - обновлённый буфер истории команд, а ещё одно вероятностное значение - наша итоговая оценка вероятности угрозы, которая сообщает, насколько небезопасно выполнять следующую команду.</p>
  <p id="vaPC">Буфер истории команд позволяет запоминать и искать паттерны, не используя для этого вектор истории команд с изменяемым размером.</p>
  <p id="Vdqu">В зависимости от архитектуры комплекса ЗИ нейросеть будет анализировать каждый процесс отдельно либо дополнительно отслеживать взаимодействие процессов и выявлять комплекты программ, каждая из которых вносит свой вклад в атаку. Также, помимо программного средства, комплекс может представлять из себя аппаратно-программное средство, так как для анализа большого числа команд нужна дополнительная мощность. Ещё расположение комплекса в отдельном аппаратном устройстве, вероятно, снизит его собственную уязвимость.</p>
  <h3 id="1iFX">Способы обучения</h3>
  <p id="dWFM">Для обучения ML-модели предлагается составить набор безопасных и заражённых программ, чтобы провести обучение с подкреплением. Ещё один вариант - создать генератор заражённых программ, чтобы провести автоматизированное генеративное обучение.</p>
  <h2 id="0adV">Предполагаемые минусы комплекса в качестве антивируса</h2>
  <ol id="Hkw2">
    <li id="kWAZ">Поскольку комплекс ЗИ будет отслеживать все потенциально небезопасные операции, это может быть <em>дорогостоящим по времени</em> решением, так как каждая команда будет иметь временную сложность в один проход второй ступени нейронной сети.</li>
    <li id="LTSE">У нейросети не будет фундаментальных знаний об аппаратной составляющей компьютера, равно как и многих знаний об операционной системе, поэтому <em>многовекторные атаки</em> с большой вероятностью будут ускользать от неё. Поэтому важно понимать, что RTA - не панацея, и использовать другие средства защиты информации, начиная с сетевых экранов и фаззинга исходных кодов программ и заканчивая аттестованными помещениями.</li>
  </ol>
  <h2 id="1U1z">Приложение А. Определения</h2>
  <p id="N0VR"><strong>Активный анализ, или анализ реального времени (RTA)</strong> - анализ вредоносной активности в реальном времени.</p>
  <p id="elu2"><strong>Пассивный анализ</strong> - анализ бинарного кода после получения программы и перед её запуском.</p>
  <p id="lxFp"><strong>ML-модель</strong> - с англ. <code>machine learning</code> - модель машинного обучения, программа, способная самостоятельно выводить закономерности на основе входящих данных.</p>
  <h2 id="dndy">Источники</h2>
  <p id="Wmxw">1. Machine Learning and Machine Safety - Виктор Шамшин, Сборник трудов V Международной студенческой конференции «Science, Culture and Youth»<br />2. Как работают антивирусы. Методы детектирования вредоносных программ - Валентин Холмогоров, Xakep.ru<br />3. Recurrent Neural Networks (RNNs): A gentle Introduction and Overview - Robin M. Schmidt, arXiv.org<br />4. Neural Dynamics on Complex Networks - Chengxi Zang &amp; Fei Wang, arXiv.org</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@titoffklim/single-thread-async</guid><link>https://teletype.in/@titoffklim/single-thread-async?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim</link><comments>https://teletype.in/@titoffklim/single-thread-async?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=titoffklim#comments</comments><dc:creator>titoffklim</dc:creator><title>Как реализовать асинхронность в одном (!) потоке</title><pubDate>Fri, 10 Jun 2022 20:07:10 GMT</pubDate><category>Код</category><description><![CDATA[Qt - кросс-платформенный фреймворк для C++ - управляет интерфейсом и всеми прикрученными к нему функциями через event loop'ы, причем интерфейс остается отзывчивым даже при отрисовке сложных компонентов. Но проблема заключается в том, что если вызвана какая-то функция, то в процессе её выполнения интерфейс не обновляется, и, по сути, приложение зависает, пока та функция не выполнится. И вот, в процессе написания чат-бота с поддержкой скриптов на Python, я подумал: что, если люди захотят написать такие скрипты, которые будут выполняться чуть дольше, чем нужно?]]></description><content:encoded><![CDATA[
  <p id="Fvbo">Qt - кросс-платформенный фреймворк для C++ - управляет интерфейсом и всеми прикрученными к нему функциями через event loop&#x27;ы, причем интерфейс остается отзывчивым даже при отрисовке сложных компонентов. Но проблема заключается в том, что если вызвана какая-то функция, то в процессе её выполнения интерфейс не обновляется, и, по сути, приложение зависает, пока та функция не выполнится. И вот, в процессе написания чат-бота с поддержкой скриптов на Python, я подумал: что, если люди захотят написать такие скрипты, которые будут выполняться чуть дольше, чем нужно?</p>
  <h2 id="LxK7">А можно ли этого избежать как-то?</h2>
  <p id="kcB7">Мне, в сущности, нужно было вызвать обработку ввода, которая выдавала ответ на экран через сигнал. Если в одном из вариантов ответа находился скрипт, я должен подождать его выполнения.</p>
  <p id="jpRj">Официальный C API от Python поддерживал только прямой вызов функции из модуля, не асинхронный, поэтому пришлось подумать о том, как вынести этот вызов в отдельный поток. И даже здесь оказалось не всё так однозначно: при инициализации среды выполнения Python ориентировался только на главный поток, и чтобы получить доступ к интерпретатору в другом потоке, нужно было вызвать пару методов - и при этом гарантировать, что программа не пытается запустить такой же поток где-нибудь ещё.</p>
  <p id="78a6">Извне функции обертка приняла вид цикла, который каждые 0.3 секунды опрашивает результат, и если ответа нет, вызывает функцию обработки событий event loop&#x27;а...</p>
  <p id="2Naw">И вот проблема!</p>
  <ol id="SmCx">
    <li id="xnRx">Если пользователь отправит ещё одно сообщение, которое вызовет скрипт, то либо произойдет ошибка segfault из-за повторного обращения к интерпретатору из другого потока, либо deadlock из-за ожидания разблокировки мьютекса на интерпретаторе, потому что он находится в том же потоке.</li>
    <li id="FKLZ">А если функция не станет ждать разблокировки мьютекса, то данные будут утеряны.</li>
  </ol>
  <p id="nDwo">Решение нашлось ровно в том месте, где ожидается от Qt. Ведь, как говорится, клин клином вышибают.</p>
  <h2 id="Y8yJ">Сигналы и слоты для обработчика</h2>
  <p id="JO8j">Нам, так или иначе, нужен обработчик задач. Пусть запрос на выполнение скрипта будет записан в структуру PythonTask, тогда мы сможем создать метод, который делает две важные вещи:</p>
  <ol id="LsDK">
    <li id="ekKI">Если мьютекс интерпретатора заблокирован, мы добавляем задачу в список задач и завершаем выполнение функции.</li>
    <li id="bHfT">Если мьютекс разблокирован, то, пока список задач не пуст, мы обрабатываем их все и отправляем при помощи сигналов, причём каждый ожидаемый промежуток времени запускаем обработку событий Qt.</li>
  </ol>
  <p id="4H2D">Как слотам понять, ответ на какую задачу прислал обработчик? Выход простой - добавить уникальный идентификатор к задаче перед отправкой в обработчик.</p>
  <h2 id="J1xL">Общие черты разработки в Qt</h2>
  <p id="PGX5">Чтобы реализовать одновременно отзывчивость интерфейса и возможность обработки сложных задач, нужно:</p>
  <ul id="B7ej">
    <li id="Th4Y">выделять сложные задачи в потоки;</li>
    <li id="VzZs">динамически опрашивать потоки о завершении;</li>
    <li id="t7Ka">в перерывах вызывать обработку событий Qt.</li>
  </ul>
  <h2 id="aFBd">Отличие от Rust</h2>
  <p id="5SfM">Qt не пытается при помощи макросов уйти в метапрограммирование потоков - например, в том же tokio асинки имеют свою низкозатратную реализацию, причём на уровне программы мы пишем код, будто каждая функция будет выполняться в отдельном потоке, в то время как эта реализация просто прерывает выполнение функции в одном месте и потом возобновляет по мере получения результата. C++ так не делает, и поэтому все функции желательно завершать, передавая результаты event loop&#x27;у и используя для этого превосходный механизм сигналов и слотов.</p>

]]></content:encoded></item></channel></rss>