Изучаем VoIP-движок Mediastreamer2. Часть 5

Материал статьи взят с моего дзен-канала.

Обнаружитель тонального сигнала

В прошлой статье мы создали измеритель уровня сигнала. В этой мы научимся обнаруживать тональный сигнал.

Имитатор пульта управления и приемника

В старые времена, когда не в каждой семье был телевизор, и у половины из них каналы переключались с помощью пассатижей, в обзорах иностранной технической прессы появилась интригующая новость, что один и производителей телевизоров снабдил свои аппараты пультом дистанционного беспроводного управления. Из подробностей было известно, что пульт работает без батареек благодаря использованию необычного подхода — пульт был механический и представлял из себя гибрид музыкального инструмента — металлофона и револьвера. В барабане револьвера находились металлические цилиндры, разные по длине, и когда боёк ударял по одному из них, цилиндр начинал звенеть на своей собственной частоте. Предположительно на ультразвуке. Электроника в телевизоре слышала этот сигнал и определив его частоту выполняла соответствующее действие — переключить канал, изменить громкость, выключить телевизор.

Сегодня мы попробуем сделать реконструкцию этой системы передачи команд, воспользовавшись нашими знаниями медиастримера.

Для имитации пульта, воспользуемся текстом нашего примера тонального генератора. Мы добавим в него управление частотой генератора от нажатий с клавиатуры и приемник с декодером, который будет выводить в консоль принятые команды. После изменения, генератор должен выдавать тональные сигналы 6 частот, которыми мы будем кодировать команды увеличения/уменьшения громкости, смены канала, включения/выключения телевизора. Для настройки детектора используется структура:

struct _MSToneDetectorDef{        char tone_name[8];           int frequency; /**<Expected frequency of the tone*/       int min_duration; /**<Min duration of the tone in milliseconds */       float min_amplitude; /**<Minimum amplitude of the tone, 1.0 corresponding to the normalized 0dbm level */ };  typedef struct _MSToneDetectorDef MSToneDetectorDef;

Детектору можно передать 10 таких структур, тем самым один детектор можно настроить на обнаружение десяти двутональных сигналов. Но мы с вами будем использовать всего шесть однотональных сигналов. Для передачи настроек детектору используется метод MS_TONE_DETECTOR_ADD_SCAN.

Чтобы детектор мог известить нас о том, что на его вход поступил сигнал с искомыми частотными составляющими, мы должны ему предоставить функцию обратного вызова, которую он запустит по такому случаю. Это делается с помощью функции ms_filter_set_notify_callback(). В качестве аргументов она получает указатель на фильтр, указатель на функцию обратного вызова, указатель на данные, которые бы мы хотели передать функции обратного вызова (данные пользователя).

При срабатывании детектора функция обратного вызова получит данные пользователя, указатель на фильтр детектора, идентификатор события, и структуру описывающую событие:

 /** * Structure carried as argument of the MS_TONE_DETECTOR_EVENT**/ struct _MSToneDetectorEvent{        char tone_name[8];       /* Имя тона которое мы ему назначили при настройке детектора. */       uint64_t tone_start_time;   /* Время в миллисекундах, когда тон был обнаружен. */ };  typedef struct _MSToneDetectorEvent MSToneDetectorEvent; 

Структурная схема обработки сигнала показана в заглавной картинке.

Ну а теперь сам код программы с комментариями.

/* Файл mstest4.c Имитатор пульта управления и приемника. */ #include <mediastreamer2/msfilter.h> #include <mediastreamer2/msticker.h> #include <mediastreamer2/dtmfgen.h> #include <mediastreamer2/mssndcard.h> #include <mediastreamer2/msvolume.h> #include <mediastreamer2/mstonedetector.h>  /* Подключаем заголовочный файл с функциями управления событиями  * медиастримера. */ #include <mediastreamer2/mseventqueue.h>  /* Функция обратного вызова, она будет вызвана фильтром, как только он  * обнаружит совпадение характеристик входного сигнала с заданными. */ static void tone_detected_cb(void *data, MSFilter *f, unsigned int event_id,         MSToneDetectorEvent *ev) {     printf("                      Принята команда: %s\n", ev->tone_name); }  int main() {     ms_init();      /* Создаем экземпляры фильтров. */     MSFilter  *voidsource = ms_filter_new(MS_VOID_SOURCE_ID);     MSFilter  *dtmfgen = ms_filter_new(MS_DTMF_GEN_ID);     MSFilter  *volume = ms_filter_new(MS_VOLUME_ID);     MSSndCard *card_playback =         ms_snd_card_manager_get_default_card(ms_snd_card_manager_get());     MSFilter  *snd_card_write = ms_snd_card_create_writer(card_playback);     MSFilter  *detector = ms_filter_new(MS_TONE_DETECTOR_ID);      /* Очищаем массив находящийся внутри детектора тонов, он описывает      * особые приметы разыскиваемых сигналов.*/     ms_filter_call_method(detector, MS_TONE_DETECTOR_CLEAR_SCANS, 0);      /* Создаем источник тактов - тикер. */     MSTicker *ticker=ms_ticker_new();      /* Соединяем фильтры в цепочку. */     ms_filter_link(voidsource, 0, dtmfgen, 0);     ms_filter_link(dtmfgen, 0, volume, 0);     ms_filter_link(volume, 0, detector, 0);     ms_filter_link(detector, 0, snd_card_write, 0);      /* Подключаем к фильтру функцию обратного вызова. */     ms_filter_set_notify_callback(detector,             (MSFilterNotifyFunc)tone_detected_cb, NULL);      /* Подключаем источник тактов. */     ms_ticker_attach(ticker,voidsource);      /* Создаем массив, каждый элемент которого описывает характеристику      * одного из тонов, который требуется обнаруживать: Текстовое имя      * данного элемента, частота в герцах, длительность в миллисекундах,      * минимальный уровень относительно 0,775В. */       MSToneDetectorDef  scan[6]=     {         {"V+",  440, 100, 0.1}, /* Команда "Увеличить громкость". */         {"V-",  540, 100, 0.1}, /* Команда "Уменьшить громкость". */         {"C+",  640, 100, 0.1}, /* Команда "Увеличить номер канала". */         {"C-",  740, 100, 0.1}, /* Команда "Уменьшить номер канала". */         {"ON",  840, 100, 0.1}, /* Команда "Включить телевизор". */         {"OFF", 940, 100, 0.1}  /* Команда "Выключить телевизор". */     };      /* Передаем в детектор тонов приметы сигналов. */     int i;     for (i = 0; i < 6; i++)     {         ms_filter_call_method(detector, MS_TONE_DETECTOR_ADD_SCAN,                 &scan[i]);     }      /* Настраиваем структуру, управляющую выходным сигналом генератора.*/     MSDtmfGenCustomTone dtmf_cfg;     dtmf_cfg.tone_name[0] = 0;     dtmf_cfg.duration = 1000;     dtmf_cfg.frequencies[0] = 440;     /* Будем генерировать один тон, частоту второго тона установим в 0.*/     dtmf_cfg.frequencies[1] = 0;     dtmf_cfg.amplitude = 1.0;     dtmf_cfg.interval = 0.;     dtmf_cfg.repeat_count = 0.;      /* Организуем цикл сканирования нажатых клавиш. Ввод нуля завершает      * цикл и работу программы. */     char key='9';     printf("Нажмите клавишу команды, затем ввод.\n"         "Для завершения программы введите 0.\n");     while(key != '0')     {         key = getchar();         if ((key >= 49) && (key <= 54))         {                 printf("Отправлена команда: %c\n", key);             /* Устанавливаем частоту генератора в соответствии с              * кодом нажатой клавиши.*/             dtmf_cfg.frequencies[0] = 440 + 100*(key-49);              /* Включаем звуковой генератор c обновленной частотой. */             ms_filter_call_method(dtmfgen, MS_DTMF_GEN_PLAY_CUSTOM,                     (void*)&dtmf_cfg);         }         ms_usleep(20000);     } }

Компилируем и запускаем программу. Если все работает правильно, то после запуска мы должны получить примерно такое поведение программы:

$ ./mstest4 ALSA lib conf.c:4738:(snd_config_expand) Unknown parameters 0 ALSA lib control.c:954:(snd_ctl_open_noupdate) Invalid CTL default:0 ortp-warning-Could not attach mixer to card: Invalid argument ALSA lib conf.c:4738:(snd_config_expand) Unknown parameters 0 ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM default:0 ALSA lib conf.c:4738:(snd_config_expand) Unknown parameters 0 ALSA lib pcm.c:2266:(snd_pcm_open_noupdate) Unknown PCM default:0 ortp-warning-Strange, sound card Intel 82801AA-ICH does not seems to be capable of anything, retrying with plughw... Нажмите клавишу команды, затем ввод. Для завершения программы введите 0. ortp-warning-alsa_set_params: periodsize:256 Using 256 ortp-warning-alsa_set_params: period:8 Using 8 

Нажимаем любые клавиши от "1" до "6", подтверждая клавишей "Enter", должен получаться примерно такой листинг:

 2 Отправлена команда: 2                       Принята команда: V- 1 Отправлена команда: 1                       Принята команда: V+ 3 Отправлена команда: 3                       Принята команда: C+ 4 Отправлена команда: 4                       Принята команда: C- 0 $

Мы видим, что тоны команд успешно отправляются и детектор их обнаруживает.

В следующей статье мы обратимся к передаче звукового сигнала по сети Ethernet с помощью RTP-протокола и тут же применим его в нашем дистанционном пульте.

ссылка на оригинал статьи https://habr.com/ru/post/496160/

Большая виртуальная конференция: Реальный опыт по защите данных от современных цифровых компаний

Привет, Хабр! Завтра, 8 апреля, состоится большая виртуальная конференция, на которой ведущие эксперты отрасли будут обсуждать вопросы защиты данных в реалиях современных киберугроз. Представители бизнеса поделятся методами борьбы с новыми опасностями, а сервис-провайдеры расскажут о том, почему сервисы киберзащиты помогают оптимизировать ресурсы и экономить деньги. Для желающих принять участие — подробное описание программы мероприятия, а также ссылка на бесплатную регистрацию под катом.

image

В наших прошлых постах мы уже говорили о том, почему традиционное резервное копирование умерло. Без дополнительной защиты от интеллектуальных угроз, без использования облачных технологий и эвристических алгоритмов резервные копии могут быть точно также повреждены вирусами и шифровальщиками, и это только одна из множества проблем современных компаний.

Мы подготовили виртуальную конференцию, которая состоится 8 апреля в 16.00 по московскому времени (2:00 BST). Двухчасовое мероприятие будет включать в себя две панельные дискуссии: «Почему устаревшие системы резервного копирования не могут противостоять современным киберугрозам», а также «Фреймворк для SMB и NIST: почему киберзащита нужна не только корпорациям».

На мероприятии будут выступать как представители Acronis, так и руководители компаний, выбравшие стратегию киберзащиты. В их числе:

  • Кристель Хейккила (Christelle Heikkila), ИТ-директор FC Arsenal,
  • Ричард Табб (Richard Tubb), эксперт по развитию ИТ-бизнеса,
  • Бертил Брендеке (Bertil Brendeke), вице-президент Acronis по направлению Cloud Europe,
  • Стэпан Бинек (Stepán Bínek), менеджер облачных продуктов в Zebra,
  • Кандид Вуэст (Candid Wuest), вице-президент Acronis Cyber Protection Research,
  • Джеймс Эр. Слэби (James R. Slaby), директор направления Cyber Protection в Acronis,
  • Уильям Деспард (William Despard), управляющий директор Teknov8 в Африке
  • Клэр Сетчвелл (Clare Satchwell), руководитель по продуктам и маркетингу в Vuzion.

Представители бизнеса расскажут о тех угрозах и проблемах, с которыми они столкнулись в последние годы. В частности, Кристель Хейккила, ИТ-директор FC Arsenal, поделится опытом перехода от разрозненных систем защиты к единому решению. Руководители сервис-провайдеров расскажут о внедрении сервисов киберзащиты (киберзащита + гибридное резервное копирование) и объяснят, почему после перехода на новые технологии снизилась нагрузка на службу техподдержки, уменьшилось количество тикетов и выросла прибыль.

Также в ходе нашей конференции будет проведена первая публичная демонстрация Acronis Cyber Protection Cloud в Европе. Новое решение представляет собой интегрированную систему с функциями ИИ. Облачный сервис сочетает в себе современные технологии резервного копирования, защиты от вредоносного ПО и управления безопасностью, включая оценку уязвимостей, контроль доставки патчей, фильтрацию URL и так далее. Ронан МакКёртен (Ronan McCurtin), вице-президент Acronis в Северной Европе и Николай Чуркин, инженер по решениям Acronis расскажут обо всех особенностях системы, ее преимуществах для бизнеса и сервис-провайдеров. Акцент будет сделан на уникальных возможностях и кейсах, которые раньше были невозможны в рамках единого сервиса или продукта.

Присоединяйтесь к нашему мероприятию. Обилие информации и наличие практического опыта гарантировано! А чтобы вам было не только интересно, но и приятно, среди участников будут разыграны призы от FC Arsenal!

ссылка на оригинал статьи https://habr.com/ru/company/acronis/blog/496176/

Береги тень смолоду

Читая этот материал, вы уже оставили свой след в цифровой вселенной. Информация о вашем нынешнем местонахождении или используемой операционной системе сохранилась в глобальном массиве больших данных и может быть использована как для благих целей, так и назойливыми рекламодателями или злоумышленниками.

Давайте сразу оговоримся, оставаться полностью «незамеченным», совсем не оставляя цифровые следы, сегодня невозможно. Что бы вы ни делали, используя свой смартфон или ноутбук, ваши ходы постоянно записываются. Более того, источником важной информации могут быть не только априори «умные устройства» — «Яндекс-станция» или «умные часы», но и, например, «умный» холодильник, фитнес-трекер или проездной на метро. Количество ваших персональных цифровых следов растёт с каждым прожитым днём, формируя совокупно вашу «цифровую тень» — цифровой «портрет» вашей личности. Портрет, довольно близкий к оригиналу.

Большие данные

Ваша «цифровая тень» и цифровые следы являются источником и основной составляющей Больших данных (Big Data) – неотъемлемой части общества потребления в эпоху современных IT-технологий, социальных сетей и масс-медиа. Big Data – это совокупность технологий получения, хранения и обработки информации, как структурированной, так и не структурированной, в первую очередь, тех самых информационных следов. Коммерческое использование Больших данных началось около 10 лет назад и первыми, кто освоил применение этой технологии были, разумеется, технологические компании – Google, Яндекс, Yahoo, а затем и Facebook, Ebay, Amazon, вКонтакте и др. Умение обрабатывать цифровые следы позволило этим бизнесам выйти на новый уровень информированности о потребностях клиентов и покупателей, зачастую превосходящий даже возможности разведывательных служб.

Источниками информации для Big Data являются практически все действия человека в информационной среде. Это поисковые системы и системы аналитики (Google Analytics, Яндекс.Метрика), социальные сети, точки захвата контактных данных (сайты, мобильные приложения и т.п.), данные, хранящиеся в cash, интернет вещей (Internet-of-things, или данные, которыми обмениваются различные «умные» устройства) и многое другое.

Большие данные используются государственными органами, в исследованиях и стратегическом прогнозировании, бизнесом для построения верной стратегии продаж или рекламной кампании. Ваши цифровые следы и полученные на их основе Большие данные на выходе дают, например, такие бизнес-решения, как персонализация товарных предложений в сети, контента на сайтах или в приложениях и e-mailрассылок. По мере совершенствования эти технологии будут ещё шире применяться в таких сферах как, например, здравоохранение, транспортная инфраструктура и безопасность, сельское хозяйство и т.д.

Цифровой след

Большие данные так же облегчают нашу жизнь в интернете и избавляют от мук потребительского выбора и части информационного шума. Однако, наш цифровой след используют не только для построения полезных алгоритмов в благих целях. Довольно легко получить доступ к вашей «цифровой тени» могут ваши недоброжелатели, конкуренты, злоумышленники или государственные структуры. Завладев таким образом сведениями, не доступными при обычном сборе информации, они в состоянии доставить вам большие неприятности. Однажды попав во всемирную сеть, ваши фото, комментарии и незашифрованная переписка останутся там навсегда, и заинтересованные лица найдут о вас любую нужную им информацию: где вы живете, где работаете и сколько зарабатываете, как проводите досуг, где любите отдыхать, какие товары покупаете, что любите пить и есть, какую музыку слушаете – практически всё, что угодно.

Возьмём, к примеру, ситуацию с вашими транзакциями или платежами по банковским картам. Во-первых, многие банки отдают сервис смс-рассылок сторонним организациям, которые собирают данные о ваших доходах и суммах и статьях расходов. Во-вторых, в ходе проведения транзакций банк получает от торговой точки множество дополнительных данных по операции — дату, время, вид товара и др. И с помощью этих данных можно вычислить где вы живёте, какие магазины посещаете, где работаете, где живут ваши родственники, ваш график работы, карту перемещений и даже наличие у вас любовницы или хронических заболеваний. Допустим, утром вы совершили покупку в магазине у дома (график дня, покупательские предпочтения), заправили машину по пути на работу (карта передвижений), совершили транзакции на работе (место работы), после работы заехали в аптеку у дома за лекарствами и подгузниками (график работы, заболевания, наличие малолетнего ребёнка). Или вы можете тратить на покупки больше, чем поступает на карту по зарплатному проекту, что говорит о наличии у вас незадекларированного дохода и так далее.

Согласитесь, исчерпывающая информация. Впоследствии эти данные часто утекают на сторону, передаются или продаются. И хорошо, если они попадают в руки маркетологов и рекламщиков, а не спецслужб, налоговой службы или мошенников.

Другой пример — определение вашего круга общения на основе цифровых следов в соцсетях. Даже если вы не указываете, допустим, школу, в которой учились или место работы, заинтересованные люди всё равно могут вычислить ваши социальные связи через карту друзей (30% ваших друзей из школы №X, а 40% работают в «Банке Y», соответственно, по этой информации можно предположить, где вы учились и работаете) и, опять же, использовать эту информацию в своих корыстных целях.

Сетевая «гигиена»

Можно ли уберечься от таких сценариев или хотя бы свести их вероятность к минимуму? Можно, но лишь отчасти. Принцип простой – чем меньше вы оставляете цифровых следов онлайн, и чем менее вы «интересны» для посторонних, тем в большей вы безопасности. Вот, что можно сделать, чтобы сохранить в неприкосновенности вашу идентичность:

  • при регистрации в социальных сетях, на сайтах и в приложениях использовать временные или специально созданные для этой цели номер телефона и адрес электронной почты;
  • не раскрывать в открытых источниках e-mail, который вы используете при регистрации аккаунтов в социальных сетях;
  • по возможности делать закрытыми свои профили и списки друзей;
  • проводить очистку кэша браузеров;
  • запретить сохранение cookies (с их помощью можно проследить историю веб-сёрфинга);
  • использовать разные браузеры для разных задач (для почты, для интернет-покупок и т.д.);
  • использовать блокираторы рекламы (частично защищает от скрытых программ);
  • пользоваться для личной переписки и обмена информации не социальными сетями, а мессенджерами с постоянным сквозным шифрованием;
  • пользоваться службами электронной почты с надёжным шифрованием;
  • пользоваться сервисом VPN или браузером со встроенным VPN для выхода в интернет;
  • использовать для веб-сёрфинга анонимную сеть Tor;
  • использовать антивирус (защищает не только от вирусов, но и от keylogger’ов, которые позволяют получить «отпечатки» вводимых паролей и переписки и даже подключаться к веб-камере);
  • пользоваться наличными деньгами вместо карт и минимизировать покупки в интернете.

Все эти способы полезны и сокращают вероятность несанкционированного использования ваших данных, но не гарантируют 100% результата. Единственный вариант избежать этого — избавится от компьютера и телефона и полностью исключить взаимодействие со всемирной сетью. Путь, согласитесь, радикальный, подходящий далеко не для всех.

Значительно логичнее использовать перечисленные правила сетевой «гигиены», но не стараться полностью избавиться от своей цифровой тени, а создавать её положительный образ и использовать себе во благо. Дело в том, что значительная часть современных работодателей, учебных заведений, конкурентов или просто ваших будущих партнёров в личной жизни, проводят так называемый репутационный анализ, прежде чем иметь с вами дело. Изучаются ваши социальные профили, комментарии, ваши активности, а работодатели просят указать ссылки на ваши аккаунты в социальных сетях.

Более того, государственные органы и спецслужбы давно и планомерно идут к тому, что можно условно назвать системой социальных профилей – это полномасштабное досье на каждого гражданина, созданное как раз на основе существующих баз данных и цифровых следов. Согласитесь, что в обоих случаях, полное отсутствие цифровой тени или её негативный характер не добавят вам плюсов.

Поэтому, лучше всего постепенно и последовательно создавать в цифровой вселенной свой положительный образ. При любом действии в сети задумывайтесь о последствиях, действуйте анонимно там, где это подсказывает логика, подчёркивайте свои положительные качества, следите за репутацией. Исправить свой негативный образ в сети крайне не просто, значит создавать свой положительный сетевой образ, светлую «цифровую тень» лучше с самых первых шагов в мировой информационной сети.

ссылка на оригинал статьи https://habr.com/ru/post/496180/

WebStorm 2020.1: улучшения в интерфейсе, поддержка Vuex и запуск Prettier при сохранении файлов

Всем привет! Мы рады представить вам первое крупное обновление WebStorm в этом году. В новой версии вы найдете много новых возможностей и долгожданных улучшений, включая поддержку Vuex и новую опцию для запуска Prettier при сохранении файлов.

webStorm-2020-1-released

Скачать 30-дневную пробную версию WebStorm 2020.1 на сайте или с помощью Toolbox App. Полную версию могут использовать обладатели действующей подписки на WebStorm или All Products Pack, а также бесплатно студенты и разработчики опенсорсных проектов.

А сейчас давайте рассмотрим основные улучшения подробнее.

Новый шрифт для работы с кодом

На протяжении всего прошлого года мы разрабатывали специальный шрифт для работы с кодом, который бы помог нашим пользователям программировать с большим комфортом и свести напряжение глаз к минимуму. Результатом наших усилий стал JetBrains Mono, новый шрифт с открытым исходным кодом. Начиная с версии 2020.1, JetBrains Mono выбран по умолчанию в WebStorm и других наших IDE. Возможность включить другой шрифт, разумеется, также осталась.

jetbrains-mono

Более полезная быстрая документация

WebStorm 2020.1 поможет вам быстрее находить соответствующую информацию о символе, т. к. быстрая документация теперь отображается при наведении курсора на этот символ, а не только при нажатии F1. Если в вашем коде есть проблема и WebStorm может помочь с ее решением, он также даст вам об этом знать, отобразив доступное быстрое исправление прямо во всплывающем окне с документацией.

docs-on-hover

При работе с JavaScript и TypeScript кодом быстрая документация покажет подробную информацию о типе и видимости символа, а также о том, где этот символ определен.

ts-quick-docs

Режим Zen для сфокусированной работы

Новый режим Zen поможет вам полностью сосредоточиться на своем коде. Сочетая в себе два режима, Distraction Free и Full Screen, он позволяет быстро включить их оба и на время изолировать то, что может отвлечь ваше внимание.

zen-mode

Чтобы попробовать новый режим, перейдите к View | Appearance | Enter Zen Mode из основного меню WebStorm или используйте всплывающее окно Switch (Ctrl+` | View mode | Enter Zen Mode).

Поддержка Vuex и Vue Composition API

Vue.js набирает популярность, поэтому мы активно работаем над тем, чтобы сделать WebStorm самой полезной IDE для работы с этим фреймворком. На этот раз мы добавили два крупных улучшения.

Начнем с того, что при работе с библиотекой Vuex вы увидите варианты автодополнения кода для символов Vue store и модулей при редактировании Vue-компонентов. WebStorm также поможет быстро перейти к определению геттеров, мутаций и действий.

vuex-completion

Во-вторых, поскольку уже можно использовать Composition API, доступный в грядущем релизе Vue 3, мы решили добавить его поддержку в WebStorm 2020.1.

vue-composition-api-support

Запуск Prettier при сохранении файлов

Благодаря новой опции Run on save for files, вы можете применить форматирование Prettier ко всем файлам, указанным в настройках WebStorm и отредактированным в текущем проекте, при сохранении этих файлов — больше не нужно настраивать file watcher или пользоваться сторонним плагином.

prettier-on-save

Помощь с выявлением грамматических и стилистических ошибок

Начиная с версии 2020.1 WebStorm поставляется в комплекте с Grazie, нашим инструментом для проверки орфографии, грамматики и стиля текста. Это поможет вам избежать грамматических ошибок при добавлении комментариев, коммитов и различных языковых конструкций.

grazie

По умолчанию Grazie включен только для английского языка и проверяет не все типы файлов на возможные грамматические ошибки. Вы можете добавить больше языков и изменить предустановленные настройки в Preferences/Settings | Editor | Proofreading (перейдите в раздел Grammar, если вы хотите настроить область проверок, посмотреть существующие правила и добавить исключения).

Новые intention-действия и инспекции

Как всегда, мы добавили несколько новых intention-действий и быстрых исправлений, чтобы помочь вам сэкономить время при работе с JavaScript и TypeScript кодом. Например, одно из новых intention-действий, доступное при нажатии на Alt+Enter, позволит быстро преобразовать существующий код в optional chaining и/или nullish coalescing.

convert-to-optional-chaining

Больше информации о новых intention-действиях и быстрых исправлениях доступно в релизном блог-посте (на английском).

Поддержка последних версий популярных технологий

В WebStorm 2020.1 вы найдете встроенную поддержку функциональности TypeScript 3.8, в том числе type-only imports/exports, private fields, и top-level await, которая поможет вам работать с ними более эффективно. Помимо этого, мы сделали работу с Angular 9 проектами проще, полностью поддержав новый формат метаданных.

Более удобное перебазирование коммитов

Действие Interactively Rebase from Here, доступное на вкладке Logs окна Git, позволяет редактировать, объединять и удалять предыдущие коммиты. Это помогает сделать историю коммитов более линейной и понятной.

rebasing-commits

В WebStorm 2020.1 вы найдете улучшенную, более интерактивную версию диалогового окна Rebasing Commits, которое открывается при вызове действия Interactively Rebase from Here. В обновленном диалоговом окне отображаются действия, которые можно применить к каждому коммиту. Он также показывает подробную информацию о каждом коммите и позволяет вам увидеть разницу и быстро сбросить примененные изменения.

Использование WebStorm для быстрого редактирования файлов

Благодаря новому режиму LightEdit, вы можете открывать файлы в отдельном окне текстового редактора, при этом не создавая и не загружая целый проект. Режим сработает, если WebStorm еще не запущен. Если WebStorm запущен, файл откроется в нем, как обычно.

Чтобы попробовать новый режим в действии, нажмите правой кнопкой мыши на файл, который вы хотите отредактировать, и выберите WebStorm из списка предложенных программ. Как вариант, вы также можете настроить command-line launcher, как описано здесь, и открыть файл, пользуясь командной строкой.

lightedit-mode

На этом всё на этот раз. Спасибо, что дочитали до конца! Еще больше подробностей вы найдете в релизном блог-посте (на английском). Вопросы, пожелания и просто мысли высказывайте в комментариях. Мы, как и всегда, будем рады ответить. Баг-репорты можно создать тут.

Команда JetBrains WebStorm
The Drive to Develop

ссылка на оригинал статьи https://habr.com/ru/company/JetBrains/blog/495228/

Apache Kafka для чайников

Данная статья будет полезной тем, кто только начал знакомиться с микросервисной архитектурой и с сервисом Apache Kafka. Материал не претендует на подробный туториал, но поможет быстро начать работу с данной технологией. Я расскажу о том, как установить и настроить Kafka на Windows 10. Также мы создадим проект, используя Intellij IDEA и Spring Boot.

Зачем?

Трудности в понимании тех или иных инструментов часто связаны с тем, что разработчик никогда не сталкивался с ситуациями, в которых эти инструменты могут понадобиться. С Kafka всё обстоит точно также. Опишем ситуацию, в которой данная технология будет полезной. Если у вас монолитная архитектура приложения, то разумеется, никакая Kafka вам не нужна. Всё меняется с переходом на микросервисы. По сути, каждый микросервис – это отдельная программа, выполняющая ту или иную функцию, и которая может быть запущена независимо от других микросервисов. Микросервисы можно сравнить с сотрудниками в офисе, которые сидят за отдельными столами и независимо от коллег решают свою задачу. Работа такого распределённого коллектива немыслима без централизованной координации. Сотрудники должны иметь возможность обмениваться сообщениями и результатами своей работы между собой. Именно эту проблему и призвана решить Apache Kafka для микросервисов.
Apache Kafka является брокером сообщений. С его помощью микросервисы могут взаимодействовать друг с другом, посылая и получая важную информацию. Возникает вопрос, почему не использовать для этих целей обычный POST – reqest, в теле которого можно передать нужные данные и таким же образом получить ответ? У такого подхода есть ряд очевидных минусов. Например, продюсер (сервис, отправляющий сообщение) может отправить данные только в виде response’а в ответ на запрос консьюмера (сервиса, получающего данные). Допустим, консьюмер отправляет POST – запрос, и продюсер отвечает на него. В это время консьюмер по каким-то причинам не может принять полученный ответ. Что будет с данными? Они будут потеряны. Консьюмеру снова придётся отправлять запрос и надеяться, что данные, которые он хотел получить, за это время не изменились, и продюсер всё ещё готов принять request.
Apache Kafka решает эту и многие другие проблемы, возникающие при обмене сообщениями между микросервисами. Не лишним будет напомнить, что бесперебойный и удобный обмен данными – одна из ключевых проблем, которую необходимо решить для обеспечения устойчивой работы микросервисной архитектуры.

Установка и настройка ZooKeeper и Apache Kafka на Windows 10

Первое, что надо знать для начала работы — это то, что Apache Kafka работает поверх сервиса ZooKeeper. ZooKeeper — это распределенный сервис конфигурирования и синхронизации, и это всё, что нам нужно знать о нём в данном контексте. Мы должны скачать, настроить и запустить его перед тем, как начать работу с Kafka. Прежде чем начать работу с ZooKeeper, убедитесь, что у вас установлен и настроен JRE.
Скачать свежею версию ZooKeeper можно с официального сайта: zookeeper.apache.org/releases.html#download
Извлекаем из скаченного архива ZooKeeper`а файлы в какую-нибудь папку на диске.
В папке zookeeper с номером версии, находим папку conf и в ней файл “zoo_sample.cfg”.

Копируем его и меняем название копии на “zoo.cfg”. Открываем файл-копию и находим в нём строчку dataDir=/tmp/zookeeper. Прописываем в данной строчке полный путь к нашей папке zookeeper-х.х.х. У меня это выглядит так: dataDir=C:\\ZooKeeper\\zookeeper-3.6.0

Теперь добавим системную переменную среды: ZOOKEEPER_HOME = C:\ ZooKeeper \zookeeper-3.4.9 и в конце системной переменной Path добавим запись: ;%ZOOKEEPER_HOME%\bin;
Запускаем командную строку и пишем команду:

zkserver

Если всё сделано правильно, вы увидите примерно следующее.

Это означает, что ZooKeeper стартанул нормально. Переходим непосредственно к установке и настройке сервера Apache Kafka. Скачиваем свежую версию с официального сайта и извлекаем содержимое архива: kafka.apache.org/downloads
В папке с Kafka находим папку config, в ней находим файл server.properties и открываем его.

Находим строку log.dirs= /tmp/kafka-logs и указываем в ней путь, куда Kafka будет сохранять логи: log.dirs=c:/kafka/kafka-logs.

В этой же папке редактируем файл zookeeper.properties. Строчку dataDir=/tmp/zookeeper меняем на dataDir=c:/kafka/zookeeper-data, не забывая при этом, после имени диска указывать путь к своей папке с Kafka. Если вы всё сделали правильно, можно запускать ZooKeeper и Kafka.

Для кого-то может оказаться неприятной неожиданностью, что никакого GUI для управления Kafka нет. Возможно, это потому, что сервис рассчитан на суровых нёрдов, работающих исключительно с консолью. Так или иначе, для запуска кафки нам потребуется командная строка.
Сначала надо запустить ZooKeeper. В папке с кафкой находим папку bin/windows, в ней находим файл для запуска сервиса zookeeper-server-start.bat, кликаем по нему. Ничего не происходит? Так и должно быть. Открываем в этой папке консоль и пишем:

 start zookeeper-server-start.bat

Опять не работает? Это норма. Всё потому что zookeeper-server-start.bat для своей работы требует параметры, прописанные в файле zookeeper.properties, который, как мы помним, лежит в папке config. Пишем в консоль:

start zookeeper-server-start.bat c:\kafka\config\zookeeper.properties 

Теперь всё должно стартануть нормально.

Ещё раз открываем консоль в этой папке (ZooKeeper не закрывать!) и запускаем kafka:

start kafka-server-start.bat c:\kafka\config\server.properties

Для того, чтобы не писать каждый раз команды в командной строке, можно воспользоваться старым проверенным способом и создать батник со следующим содержимым:

start C:\kafka\bin\windows\zookeeper-server-start.bat C:\kafka\config\zookeeper.properties timeout 10 start C:\kafka\bin\windows\kafka-server-start.bat C:\kafka\config\server.properties

Строка timeout 10 нужна для того, чтобы задать паузу между запуском zookeeper и kafka. Если вы всё сделали правильно, при клике на батник должны открыться две консоли с запущенным zookeeper и kafka.Теперь мы можем прямо из командной строки создать продюсера сообщений и консьюмера с нужными параметрами. Но, на практике это может понадобиться разве что для тестирования сервиса. Гораздо больше нас будет интересовать, как работать с kafka из IDEA.

Работа с kafka из IDEA

Мы напишем максимально простое приложение, которое одновременно будет и продюсером и консьюмером сообщения, а затем добавим в него полезные фичи. Создадим новый спринг-проект. Удобнее всего делать это с помощью спринг-инициалайзера. Добавляем зависимости org.springframework.kafka и spring-boot-starter-web


В итоге файл pom.xml должен выглядеть так

Для того, чтобы отправлять сообщения, нам потребуется объект KafkaTemplate<K, V>. Как мы видим объект является типизированным. Первый параметр – это тип ключа, второй – самого сообщения. Пока оба параметра мы укажем как String. Объект будем создавать в классе-рестконтроллере. Объявим KafkaTemplate и попросим Spring инициализировать его, поставив аннотацию Autowired.

@Autowired private KafkaTemplate<String, String> kafkaTemplate;

В принципе, наш продюсер готов. Всё что осталось сделать – это вызвать у него метод send(). Имеется несколько перегруженных вариантов данного метода. Мы используем в нашем проекте вариант с 3 параметрами — send(String topic, K key, V data). Так как KafkaTemplate типизирован String-ом, то ключ и данные в методе send будут являться строкой. Первым параметром указывается топик, то есть тема, в которую будут отправляться сообщения, и на которую могут подписываться консьюмеры, чтобы их получать. Если топик, указанный в методе send не существует, он будет создан автоматически. Полный текст класса выглядит так.

@RestController @RequestMapping("msg") public class MsgController {      @Autowired     private KafkaTemplate<String, String> kafkaTemplate;      @PostMapping     public void sendOrder(String msgId, String msg){         kafkaTemplate.send("msg", msgId, msg);     } } 

Контроллер мапится на localhost:8080/msg, в теле запроса передаётся ключ и само сообщений.
Отправитель сообщений готов, теперь создадим слушателя. Spring так же позволяет cделать это без особых усилий. Достаточно создать метод и пометить его аннотацией @KafkaListener, в параметрах которой можно указать только топик, который будет слушаться. В нашем случае это выглядит так.

@KafkaListener(topics="msg")

У самого метода, помеченного аннотацией, можно указать один принимаемый параметр, имеющий тип сообщения, передаваемого продюсером.
Класс, в котором будет создаваться консьюмер необходимо пометить аннотацией @EnableKafka.

@EnableKafka @SpringBootApplication public class SimpleKafkaExampleApplication {      @KafkaListener(topics="msg")     public void msgListener(String msg){         System.out.println(msg);     }      public static void main(String[] args) {         SpringApplication.run(SimpleKafkaExampleApplication.class, args);     } }

Так же в файле настроек application.property необходимо указать параметр консьюмера groupe-id. Если этого не сделать, приложение не запуститься. Параметр имеет тип String и может быть любым.

spring.kafka.consumer.group-id=app.1

Наш простейший кафка-проект готов. У нас есть отправитель и получатель сообщений. Осталось только запустить. Для начала запускаем ZooKeeper и Kafka с помощью батника, который мы написали ранее, затем запускаем наше приложение. Отправлять запрос удобнее всего с помощью Postman. В теле запроса не забываем указывать параметры msgId и msg.

Если мы видим в IDEA такую картину, значит всё работает: продюсер отправил сообщение, консьюмер получил его и вывел в консоль.

Усложняем проект

Реальные проекты с использованием Kafka конечно же сложнее, чем тот, который мы создали. Теперь, когда мы разобрались с базовыми функциями сервиса, рассмотрим, какие дополнительные возможности он предоставляет. Для начала усовершенствуем продюсера.
Если вы открывали метод send(), то могли заметить, что у всех его вариантов есть возвращаемое значение ListenableFuture<SendResult<K, V>>. Сейчас мы не будем подробно рассматривать возможности данного интерфейса. Здесь будет достаточно сказать, что он нужен для просмотра результата отправки сообщения.

@PostMapping public void sendMsg(String msgId, String msg){     ListenableFuture<SendResult<String, String>> future = kafkaTemplate.send("msg", msgId, msg);     future.addCallback(System.out::println, System.err::println);     kafkaTemplate.flush(); }

Метод addCallback() принимает два параметра – SuccessCallback и FailureCallback. Оба они являются функциональными интерфейсами. Из названия можно понять, что метод первого будет вызван в результате успешной отправки сообщения, второго – в результате ошибки.Теперь, если мы запустим проект, то увидим на консоли примерно следующее:

SendResult [producerRecord=ProducerRecord(topic=msg, partition=null, headers=RecordHeaders(headers = [], isReadOnly = true), key=1, value=Hello, world!, timestamp=null), recordMetadata=msg-0@6]

Посмотрим ещё раз внимательно на нашего продюсера. Интересно, что будет если в качестве ключа будет не String, а, допустим, Long, а в качестве передаваемого сообщения и того хуже – какая-нибудь сложная DTO? Попробуем для начала изменить ключ на числовое значение…

Если мы укажем в продюсере в качестве ключа Long, то приложение нормально запуститься, но при попытке отправить сообщение будет выброшен ClassCastException и будет сообщено, что класс Long не может быть приведён к классу String.

Если мы попробуем вручную создать объект KafkaTemplate, то увидим, что в конструктор в качестве параметра передаётся объект интерфейса ProducerFactory<K, V>, например DefaultKafkaProducerFactory<>. Для того, чтобы создать DefaultKafkaProducerFactory, нам нужно в его конструктор передать Map, содержащий настройки продюсера. Весь код по конфигурации и созданию продюсера вынесем в отдельный класс. Для этого создадим пакет config и в нём класс KafkaProducerConfig.

@Configuration public class KafkaProducerConfig {      private String kafkaServer="localhost:9092";      @Bean     public Map<String, Object> producerConfigs() {         Map<String, Object> props = new HashMap<>();         props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,                 kafkaServer);         props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,                 LongSerializer.class);         props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,                 StringSerializer.class);         return props;     }      @Bean     public ProducerFactory<Long, String> producerFactory() {         return new DefaultKafkaProducerFactory<>(producerConfigs());     }      @Bean     public KafkaTemplate<Long, String> kafkaTemplate() {         return new KafkaTemplate<>(producerFactory());     } } 

В методе producerConfigs() создаём мапу с конфигурациями и в качестве сериализатора для ключа указываем LongSerializer.class. Запускаем, отправляем запрос из Postman и видим, что теперь всё работает, как надо: продюсер отправляет сообщение, а консьюмер принимает его.
Теперь изменим тип передаваемого значения. Что если у нас не стандартный класс из библиотеки Java, а какой-нибудь кастомный DTO. Допустим такой.

@Data public class UserDto {     private Long age;     private String name;     private Address address; }  @Data @AllArgsConstructor public class Address {     private String country;     private String city;     private String street;     private Long homeNumber;     private Long flatNumber; }

Для отправки DTO в качестве сообщения, нужно внести некоторые изменения в конфигурацию продюсера. В качестве сериализатора значения сообщения укажем JsonSerializer.class и не забудем везде изменить тип String на UserDto.

@Configuration public class KafkaProducerConfig {      private String kafkaServer="localhost:9092";      @Bean     public Map<String, Object> producerConfigs() {         Map<String, Object> props = new HashMap<>();         props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,                 kafkaServer);         props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,                 LongSerializer.class);         props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,                 JsonSerializer.class);         return props;     }      @Bean     public ProducerFactory<Long, UserDto> producerFactory() {         return new DefaultKafkaProducerFactory<>(producerConfigs());     }      @Bean     public KafkaTemplate<Long, UserDto> kafkaTemplate() {         return new KafkaTemplate<>(producerFactory());     } }

Отправим сообщение. В консоль будет выведена следующая строка:

Теперь займёмся усложнением консьюмера. До этого наш метод public void msgListener(String msg), помеченный аннотацией @KafkaListener(topics=«msg») в качестве параметра принимал String и выводил его на консоль. Как быть, если мы хотим получить другие параметры передаваемого сообщения, например, ключ или партицию? В этом случае тип передаваемого значения необходимо изменить.

@KafkaListener(topics="msg") public void orderListener(ConsumerRecord<Long, UserDto> record){     System.out.println(record.partition());     System.out.println(record.key());     System.out.println(record.value()); }

Из объекта ConsumerRecord мы можем получить все интересующие нас параметры.

Мы видим, что вместо ключа на консоль выводятся какие-то кракозябры. Это потому, что для десериализации ключа по умолчанию используется StringDeserializer, и если мы хотим, чтобы ключ в целочисленном формате корректно отображался, мы должны изменить его на LongDeserializer. Для настройки консьюмера в пакете config создадим класс KafkaConsumerConfig.

@Configuration public class KafkaConsumerConfig {      @Value("${spring.kafka.bootstrap-servers}")     private String kafkaServer;      @Value("${spring.kafka.consumer.group-id}")     private String kafkaGroupId;      @Bean     public Map<String, Object> consumerConfigs() {         Map<String, Object> props = new HashMap<>();         props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, kafkaServer);         props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, LongDeserializer.class);         props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);         props.put(ConsumerConfig.GROUP_ID_CONFIG, kafkaGroupId);         return props;     }      @Bean     public KafkaListenerContainerFactory<?> kafkaListenerContainerFactory() {         ConcurrentKafkaListenerContainerFactory<Long, UserDto> factory =                 new ConcurrentKafkaListenerContainerFactory<>();         factory.setConsumerFactory(consumerFactory());         return factory;     }      @Bean     public ConsumerFactory<Long, UserDto> consumerFactory() {         return new DefaultKafkaConsumerFactory<>(consumerConfigs());     } }

Класс KafkaConsumerConfig очень похож на KafkaProducerConfig, который мы создавали ранее. Здесь так же присутствует Map, содержащий необходимые конфигурации, например, такие как десериализатор для ключа и значения. Созданная мапа используется при создании ConsumerFactory<>, которая в свою очередь, нужна для создания KafkaListenerContainerFactory<?>. Важная деталь: метод возвращающий KafkaListenerContainerFactory<?> должен называться kafkaListenerContainerFactory(), иначе Spring не сможет найти нужного бина и проект не скомпилируется. Запускаем.

Видим, что теперь ключ отображается как надо, а это значит, что всё работает. Конечно, возможности Apache Kafka далеко выходят за пределы тех, что описаны в данной статье, однако, надеюсь, прочитав её, вы составите представление о данном сервисе и, самое главное, сможете начать работу с ним.
Мойте руки чаще, носите маски, не выходите без необходимости на улицу, и будьте здоровы.

ссылка на оригинал статьи https://habr.com/ru/post/496182/