Подписаться на блог

Фрирайтинг, заметки, шитпостинг и все подряд (18+)

Позднее Ctrl + ↑

Как слияние провайдеров ломает интернет

Взаимодействие с интернет-провайдерами в моей жизни происходит довольно редко, но “редко да метко”, если оно и происходит, то не обходится парой звонков в поддержку, а разрастается до чего-то более долгого и не нужного ни мне, не сотрудникам провайдера. Эта история — не исключение.

Повествование стоит начать с того, что провайдер, оказывающий мне услуги интернет-соединения решил объединиться с другим провайдером и “перевести” к нему своих пользователе, в виду чего должны были произойти миграции учётных записей для личных кабинетов, учётных записей для PPPoE подключений, счета и так далее.

Как обычно, всё прошло не очень гладко. То, что у меня изменился счёт я узнал только после звонка в поддержку. То, что у меня изменили данные для доступа в личный кабинет, я узнал, когда попытался в него залогиниться. Но тут всё интереснее, личный кабинет моего провайдера вообще перестал работать, ведь даже с данными, которые мне прислали после звонка в поддержку, я войти не смог.

Но самое печальное — у меня не работал интернет, просто не проходило подключение, судя по ошибкам, из-за неверных кредов. Я несколько раз позвонил в поддержку, то и дело мне оформляли тикеты, просили подождать обратного звонка (конечно же, не перезванивали), передавали мою проблему “более опытным” и “ответственным за это” людям, но ничего не менялось.

Прождав некоторое время я решил действовать более активно, но, как-то без необходимости звонить в поддержку. Первым делом я попробовал зайти в личный кабинет через сайт провайдера, который поглощает моего провайдера, и… успешно вошел по своим старым кредам. То есть провайдер-покупатель подготовился, перенёс данные, всё заинтегрировал, а мой текущий провайдера просто всё сломал даже на своей стороне, хотя ему и делать ничего особо не надо было.

Это была моя первая победа, на которой я, конечно же, не остановился. Уверенными кликами я проследовал в настройки профиля и увидел пункт, позволяющий изменить креды для PPPoE-подключения. Предвкушая близкую победу я вбил новые креды и получил ошибку, несколько попыток — все ошибочные. В этот момент я уже хотел прекратить свои попытки получения заветного доступа в интернет, но внезапно вспомнил, что я же “веб-разработчик”. Открываю вкладку “Network”, обновляю креды и в ответе получаю понятную ошибку, что в имени пользователя содержатся недопустимые символы, убираю их — запрос проходит, креды обновляются, интернет работает.

Как так получилось, что мой провайдер даже не проверил совместимость логинов пользователей и перенёс всю базу к другому провайдеру, а свою сломал, и почему поддержка ну вообще никак не могла помочь, я не знаю, но хорошо, что провайдер-покупатель сделал всё более-менее нормально.

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

Хотя нет, один вывод всё-такие есть: когда что-то на каком-то сайте не работает, нажимаем F12 и смотрим в консоль и на запросы, так всё понятнее станет.

Диплом NaN. The end

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

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

После всего вот этого взял отпуск на пару недель (жаль, что он почти завершился), провел некоторые мероприятия (воркшопы и лекции), провёл практику у студентов, наигрался в игры и поконтрибьютил во всякие интересные проекты https://github.com/WebPurple.

Теперь надо намечать дальнейшие планы, отказываться от привычки играть в игры и изучать всякое новое, в планах есть погрузиться в Vue и PWA, а если брать бэкенд, то чуть глубже пощупать NestJS. Также, вероятно, стоит дочитать кучку начатых книг и, всё-таки, попробовать писать что-то осмысленное и конкретное в блок, но это — как пойдёт.

На этом можно завершить цикл публикаций про диплом, вернусь к нему через пару лет, когда буду писать магистерскую “диссертацию”.

Диплом 5. UI, FrontEnd

Со всякими сложностями, возникшими в начале написания клиентской части разобрались, теперь можно и поверстать.

Январь 2018

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

Самым популярным оказался Material-UI, его и возьмём, такой дизайн сейчас вроде модный, так что сойдёт.

Дока у них, конечно, странновата, хотя, может я где-то не там и как-то не так смотрю...

Попытался обратиться к API, и всё сломалось, оказалось, сначала не к тому эндпоинту обращался, а я уже начал паниковать.

Только сейчас узнал, что `fetch` не уходит в `catch`, если сервер отдаёт не, на что потратил где-то полчаса, отыскивая причину возникающих ошибок. Подключил `axios`, не понимаю, почему сразу так не сделал.

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

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

По дизайну всё выходит ну очень не очень, но мне как-то лень что-то нормальное придумывать (да и не умею я в дизайн). От адаптива, вероятно тоже откажусь в итоговой версии, но это не точно.

Видимо, систему загрузки аватаров и подобного нужно будет как-то переписать...

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

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

Вчера в `app.use(express.static(’build’))` забыл дописать `/client`, из-за чего у меня файл сервера торчал наружу, фейл на фейле, хорошо, в прод это не пошло :wink:

<off_topic>
Думаю впилить сюда какую-то систему комментариев, однозначно не Disqus, а других вариантов особо и нет. Facebook’ом из моего окружения мало кто пользуется, у Twitter нет виджета комментариев, а ВК я просто не хочу.

Самый явный вариант — накостылить комментарии на основе Issues на GitHub, только тогда для комментирования нужен будет там аккаунт, но вот как раз это есть у всего моего окружения.

Идея годная, но с одной стороны, с другой — те, кто хотят что-то обсудить и так пишут мне, например, в Telegram, а обсуждение чего-то, что не относится к репозиторию в его issues — использование не по теме, да и вообще оверинжениринг выйдет какой-то.
</off_topic>

Чуть-чуть пофиксил работу сервера и своих Middleware, только защитку от брута надо бы помягче сделать и фильтр доступных эндпоинтов выставить.

Выставил — всё поломалось. Не понимаю, почему, но всё где-то падает.

Кажется, я починил. Но почему оно сломалось, так и не понял.

Пытаюсь запилить изменение пароля, на фронте всё гуд, а вот на бэке, как оказалось, я там просто заглушку оставил...

Всё поправил, роль сыграл один злополучный `await` и вызов метода.
#np


Зачем-то запилил комментарии в блог (сюда), которые работают на основе... GitHub Gists.
Потестировать можно на посте «Каррирование в JS».
А сейчас — самое время писать часть диплома для работы с сущностями типа «эвент». Ну или подумать над идеей для хакатона.

Хватит лениться, пора запилить добавление эвента.

Отодвинул разработку на «когда-нибудь»...

Март 2018

Первым делом сделал возможность собрать докер-контейнеры. Теперь всё цивильно: 3 контейнера (nginx, mongodb, nodejs). Контейнер с nginx проксирует запросы на ноду и балансит нагрузку, внутри ноды крутится кластер процессов ноды под pm2. В целом неплохо. На эту тему написал бы отдельный пост, но пока особо времени нет.

Смысла распределять нагрузку nginx’ом пока нет, поэтому с nodejs только один контейнер

Теперь решил отказаться от Google-Material кита для React и перешёл на Ant Design. С формами тут всё гораздо лучше, логин и регистрацию накидал довольно быстро.

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

Окончательно перетащил всё, что было, на новый дизайн. Параллельно несколько багов пофиксил и неплохо переделал логику редактирования профиля и загрузки аватарки.

Технология блокчейн и её применение

С докладом про блокчейн, его достоинства, недостатки и хайп я выступил на WebPurple Meetup #25.

На форуме «СТНО-2018» в секции «Информационные системы и защита информации» я выступил с докладом «Применение технологии блокчейн в области защиты информации и его недостатки».

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

Введение

Первая ассоциация с блокчейном — биткоин и другие криптовалюты. Однако, блокчейн, как технология, не обязательно связан с ними и абсолютно от них не зависит.

Блокчейн — цепочка блоков, представляющая собой связанный список. Его основные концепции: распределенность, одноранговость и защищенность. Распределенный “реестр” хранит историю всех операций между узлами одноранговой сети в виде блоков информации.

В общем случае каждый блок характеризуется следующими параметрами:

  • индекс;
  • временная отметка;
  • данные;
  • хеш текущего блока;
  • хеш предыдущего блока.

Схематичное представление блокчейна

Хешами называют результаты хеширования.

Хеширование — это преобразование массива входных данных в битовую строку фиксированной длины, выполняемое определённым алгоритмом[1].

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

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

Применение блокчейна в области распределённых вычислений и BigData

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

Число вычислительных устройств в мире с хорошими показателями вычислительных мощностей постоянно растёт, однако “КПД” этих вычислительных мощностей падает. При среднестатистическом использовании персонального компьютера большую часть времени центральный и графический процессоры в лучшем случае используются на 30%.
Неиспользуемые мощности персональных компьютеров, серверов и даже смартфонов могут приносить пользу, производить вычисления и решать какие-то задачи, если использовать давно существующий подход распределённых вычислений.

Распределенные вычисления — способ решения трудоемких вычислительных задач с использованием нескольких компьютеров, чаще всего объединённых в параллельную вычислительную систему[2].

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

Распределённая сеть устройств на основе блокчейна

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

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

Схематичные представления различных типов сетей

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

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

Применение блокчейна в области информационной безопасности веб-систем

С точки зрения информационной безопасности, блокчейн — это технология, которая помогает шифровать все действия, выполняемые с файлом или объектом, в хеш. Фактически, это не совсем шифрованием, но оно не может быть отменено, изменено и или вскрыто простыми способами, в то же время все манипуляции с зашифрованными блоками остаются полностью прозрачными: всегда известно, какие транзакции были выполнены, когда и кем. Такой подход к обеспечению безопасности данных открывает новые возможности в области безопасности веб-приложений.

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

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

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

Блокчейн предоставляет множество возможностей для обнаружения и предотвращения хакерских атак на веб-сайты. Признаки DDoS-атак сохраняются в блоки, и при повторном обнаружении подобных атак доступ злоумышленнику будет ограничен, такой подход уже используют PayPal, Twitter, Spotify и другие крупные компании.

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

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

Диплом 4. Redux, роутер, SSR

Сегодня я начинаю писать клиентскую часть диплома. Первым делом надо всё донастроить, сконфигурировать и связать с роутером и redux’ом.

Втащить Redux несложно, сложно его подключить нормально и прокинуть всё через роуты. Так ещё и ESlint ругается на код типа:

class App extends React.Component {
  methodName = () => {
    /*Говорит, что methodName undefined =/ */
  }
}

Окей, ESlint оказался как-то слишком старым, обновил — вроде всё завелось.

Так, вроде бы заработало, успел всё сломать и починить пару раз. `react-router-redux` заюзать всё-таки пришлось. Пока далеко от роутинга не ушёл, нужно серверный рендеринг сделать.

Серверный рендеринг + react + redux = вообще ад какой-то. Что-то то одно, то другое ломается, мануалы везде разные, ЧИТО ДЕЛАТЬ.

Сейчас, например, babel-node ну никак не хочет модключать стили в изоморфный компонент со стороны сервера.

Ладно, решил уже не заморачиваться с «горячей» отладкой SSR, поэтому его только после билда можно проверить. Что касается мануалов — самый подходящий оказался на [codeburst](https://codeburst.io/react-isomorphic-universal-app-w-nodejs-redux-react-router-v4-be80aa57dcaf). Теперь рендеринг на сервере работает, но вот правильно или нет я пока не совсем разобрался.

Удалил `react-router-redux`, ибо не так он уж мне и нужен. Я так-то пока не придумал, зачем мне вообще в этом проекте Redux.

Всё-таки у меня есть предположение, что менеджмент состояний я умудрился сломать, но с проблемами буду разбираться по мере их поступления.

Хм, опять же это всего диплом, а я не планировал делать SSR для кого-то кроме поисковых ботов, так что пока вообще всё неплохо идёт.

Так, всплыло куча косяков со статикой и подобным, но сейчас исправлено всё, кроме, конечно, режима разработки, в котором у меня NodeJS через babel запускался, но теперь-то там в каких-то местах в компоненты стили импортируются, в результате чего babylon падает с ошибкой.

Поправил dev-сборку, а всё ломалось из-за того, что где-то там, через 2 файла подключался компонент со стилями, чего babel терпеть не желал. В процессе ещё со статикой нахватал проблем и gzip, но там я над фиксами долго думал по причине невнимательного чтения доков.

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

Больше они не работают, т. к. блог уже пару раз переехал

Под конец дня зачем-то добавил в блог Github emoji :sunglasses: (чуть-чуть пописал на jQuery).

А сейчас пора почитать что-то интересное и отдыхать, например, «REST is the new SOAP», а так же пара ответов «A Response to REST is the new SOAP» и «Still Going on REST is the new SOAP».

WebPurple Telegram Bot

В последние пару недель я пытаюсь активно саморазвиваться, изучать что-то новое и делать чисто из интереса, даже диплом писать начал.
В первую очередь мой интерес направлен на NodeJS и всё вот это серверное, поэтому дальше BackEnd’а дипломного проекта я не дошёл, но разговор не об этом.

В Рязани наиболее активным и растущим сообществом разработчиков является WebPurple, к которому я себя смело могу отнести, ибо я являюсь активным участником (ну, я так считаю).

Для обсуждения всякого разного был создан чатик в Telegram, ну и чтобы привнести интерактивности, было принято решение сделать какого-нибудь бота, чтоб прямо круто всё было.

Изначально бот предполагался в виде типичного бота из IRC-каналов, но в итоге обсуждения он перешёл в разряд «самостоятельных» ботов. Разработкой решил заниматься я, однако в плане различных особенностей на уровне разработки, языка (NodeJS) и его использования мне помогали коллеги, чему я очень рад и благодаря чему я опять же узнал много нового.

Бот не должен был быть сложным и нагруженным, его задачей было просто джелиться информацией, составленный список функций выглядел как-то так:

  • По запросу отправлять последние новости;
  • По запросу отправлять информацию о планируемых мероприятиях;
  • По запросу отправлять ссылочки на сообщества, репозитории и всякое такое;
  • Дать юзеру возможность подписаться на рассылку новостей и как только, так сразу слать ему посты.

Вроде бы всё, изначально информацию планировалось тащить из API нашего сайта, но потом всё-таки передумали, и теперь тащим всё прямиком из группы ВКонтакте, ибо она в большей части кейсов является как бы первоисточником всего и вся.

Дабы упростить процесс разработки я, недолго думая, ввёл следующую команду в терминал и был рад.

npm install --save node-telegram-bot-api

Первые сложности возникли, когда я пытался с Long-Pulling соединения всё на WebHook’и переделать, но это я мануалы плохо читал.
По итогу первая версия, которая просто отдавала «статику» завелась за пару часов. А всё просто потому, что надо учитывать всякие слэши и вот это всё, ну и то, что у меня не чисто бот, а Express, «внутри» которого живёт бот.

const TelegramBot = require('node-telegram-bot-api');
const botUrl = `/bot${botToken}`;
const bot = new TelegramBot(botToken, {
  onlyFirstMatch: true,
});

app.post(botUrl, (req, res) => {
  bot.processUpdate(req.body);
  res.sendStatus(200);
});

app.listen(port, () => {
  console.log(`Express server is listening on ${port}`);
  bot.setWebHook(`https://example.com${botUrl}`);
});

Стоит учесть, что мне было лень разбираться с нормальным выстраиванием процессов разработки бота, поэтому всё отлаживал я прямо на Heroku, деплоя туда новую версию, т. к. всё было быстро, неудобств я не испытывал. Но для вероятных контрибьюторов я упростил задачу и сделал Long-Pooling в development-окружении, а WebHook’и только в production:

const TelegramBot = require('node-telegram-bot-api');
const botUrl = `/bot${botToken}`;
const bot = new TelegramBot(botToken, {
  onlyFirstMatch: true,
  polling: !isProduction,
});

app.listen(port, () => {
  console.log(`Express server is listening on ${port}`);
  if (isProduction) {
    bot.setWebHook(`${hookUrl}${botUrl}`);
  }
});

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

Затем пришла пора работать с API ВКонтакте, обрабатывать хуки от Callback API и вот это всё. Документацию я опять же читал не совсем внимательно, но когда в ответ на запрос нужно отправлять помимо статуса 200 ещё и текст `ok` именно маленькими буквами было для меня чуть-чуть неожиданно.
А перед этим на этот же запрос нужно отправлять ответ в виде «сколько-то_там_значного» кода. Чтобы не производить деплой пару раз подряд я вынес эту переменную в ENV.

Callback API — лучшая часть VK API, потому что... использовать его ну очень просто. Получить текст записи, только что опубликованной в группе — элементарно! Однако, я хотел дать пользователям возможность получать контент по некоторому набору категорий, которые задавались в постах хэш-тэгами. Несколько реализаций «парсера» были испробованы, в итоге остановился на варианте ниже, т. к. проще, удобнее, теги можно обработать перед отправкой:

const formattedText = text.replace(
  regExp,
  (_, type) => {
    types.push(type);
    return `#${type}`;
  }
);

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

Таким образом получение планируемых эвентов выглядит как-то так:

fetch(/* Получаем 5 групп по определённому названию, с типом "event", старт которых только будет в будущем */)
  .then(r => r.json())
  .then((r) => {
    // Для вязкости добавим проверок
    if (r.response && r.response.items && r.response.items.length) {
      const groups = r.response.items.map(g => g.id);
      fetch(/* О каждой группе получим информацию */)
        .then(res => res.json())
        .then((res) => {
          if (res.response && res.response.length) {
            const processEvent = vkEventProcess(uid, bot);
            res.response
              .sort((a, b) => a.start_date - b.start_date)
              .reduce(
                // Тут "чейним" отправку сообщений, чтобы был точный порядок
                (promise, event) => promise.then(
                  () => processEvent(event),
                  err => console.log(err),
                ),
                Promise.resolve(),
              );
          }
        });
    } else {
      bot.sendMessage(uid, getNoEventsMessage(lang));
    }
  });

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

Описание `member_status`

Потом были этапы отладки, поиска багов и вот этого всего «предрелизного». Затем проведены интеграции, написаны тесты, небольшой README, добавлена возможность нормальной локальной отладки (был бы localetunnel, была б сказка, но там всё от параметров сети сильно зависит), CI, простой деплой на собственный инстанс Heroku и... «релиз».


После релиза я обнаружил, что событие «Репост» у ВКонтакте работает не совсем так, как я ожадал, поэтому пришлось быстренько фиксить, но все подписчики бота тогда уже получили невалидное сообщение.

Пост изначально планировался каким-то более содержательным и интересным, но из-за своей лени я остановился просто на перечислении сложностей, которые возникли в процессе разработки. Это всё-таки просто мой дневник в стиле «а что я вообще тогда делал».

Посмотреть на бота можно здесь: Telegram Bot.
Поучаствовать в разработке, предложить функционал и сообщить о багах можно здесь: GitHub.

Диплом, часть 3. MongoDB, API, Cloudinary

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

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



В общем и целом объясняют не совсем так, как мне хотелось бы и как объяснял бы я именно взаимодействие NodeJS, работу Express. Но непосредственно по `passport.js` меня всё устраивает.

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

—-

Долго сидел и искал непонятную ошибку, которая всё мне роняла, причиной оказалась моя невнимательность и особенность Express, в 1 и 2 строке сниппета res не одно и то же, т. к. в зависимости от числа параметров в функцию пробрасываются отличающиеся параметры:

export default (err, req, res, next) => ...
export default (err, req, res) => ...

Помимо всего `passport.js` как-то не особо укладывается в архитектуру приложения, которую я сначала хотел реализовать. Пока сделаю чисто так, чтобы просто работало, а затем уже буду рефакторить.

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

После деплоя все вызовы API работают, это гуд. Прикручиваю токены.

Всё оказалось гораздо проще, и Passport мне вообще не нужен будет, ибо есть JWT. День в пустую.

Окей, с API логина и регистрации разобрались. Теперь накидаем простые варианты API и чуть расширим схемы моделей.
Конечно, я шифрую пароли bcrypt’ом. Сейчас объект юзера в БД хранится в примерно таком виде:

{
  "_id": {
    "$oid": "5a5cbe2425ac100014571bd4"
  },
  "login": "root",
  "password": "$2a$10$YWEDx35UrhtLOg1x2FPP5ezxPP7XSbFfuYsvpdWblGGbo9nqLLzZe",
  "email": "[email protected]",
  "__v": 0
}

Сделал API для юзеров. Вроде бы всё ок, нужно только продумать, как быть с аватарами и всякими такими файлами.

Серверная часть готова абсолютно, если исключить всякие особенности и, конечно, загрузку файлов.

Несколько часов промучался с загрузкой файлов, а все проблемы были в правах и неверных заголовках. Теперь вроде бы окей работает загрузка отдельных файлов в виде `form-data`. За это спасибо `Multer.js`. Теперь ещё впилю поддержку облака `cloudinary`.

Собирался накостылять своё решение, но вовремя нашёл `multer-storage-cloudinary.js`. Закинул в деплой, теперь осталось чуть-чуть протестировать.

Окончательная версия выглядит примерно так:

Routes.js

import express from 'express';
import checkToken from '../middlewares/checkToken';
import * as FileController from '../controllers/file';

const router = express.Router();
router.post('/avatar', checkToken, FileController.uploadFile('avatar'), FileController.uploadController);
router.post('/event', checkToken, FileController.uploadFile('event'), FileController.uploadController);

export default router;

Controllers.js

import path from 'path';
import multer from 'multer';
import cloudinary from 'cloudinary';
import cloudinaryStorage from 'multer-storage-cloudinary';
import config from '../config';

cloudinary.config(config.cloudinary);

const storage = fieldName => (config.isProduction ?
  cloudinaryStorage({
    cloudinary,
    folder: `${config.uploadDirectory}/${fieldName}`,
    allowedFormats: ['jpg', 'jpeg', 'png', 'gif'],
    filename: (req, file, callback) => {
      callback(null, req.user._id);
    },
  }) :
  multer.diskStorage({
    destination: config.uploadDirectory,
    filename: (req, file, callback) => {
      callback(null, req.user._id + path.extname(file.originalname));
    },
  })
);

export const uploadFile = fieldName => multer({
  storage: storage(fieldName),
  limits: { fileSize: config.maxFileSize },
}).single(fieldName);

export const uploadController = async (req, res, next) => {
  if (req.file) {
    if (config.isProduction) {
      return res.json({
        fileUrl: req.file.url,
      });
    }
    const filePath = req.file.destination.slice(req.file.destination.indexOf('/') + 1);
    return res.json({
      fileUrl: `/${filePath}${req.file.filename}`,
    });
  }

  return next({
    status: 500,
    message: 'Upload error!',
  });
};

Проверить работу можно следующим образом (отправлять запросы можно, например, Postman’ом):

  1. Регистрируемся, послав post-запрос на http://diploma.ifedyukin.ru/api/user/register, формат `x-www-form-urlencoded`, поля: login, password, email (что в них отправлять, думаю, не стоит комментировать); последующий вход осуществляется отправкой такого же запроса, только на http://diploma.ifedyukin.ru/api/user/login и без поля «email» — в ответ придёт токен авторизации;
  2. В ответе получаем объект, в котором нас интересует поле `token`, содержимое этого поля вносим в заголовок `Authorization`;
  3. Посылаем post-запрос на http://diploma.ifedyukin.ru/api/file/avatar, формата `form-data`, с полем `avatar`, в котором будет лежать картинка.

Прикрутил аналитику от «Keen.io» и логгирование от «Logentries». Теперь могу смотреть статистику всяких событий, отслеживать «атаки» (сегодня в 4 утра кто-то пытался подбирать пароли к учетным записям, которых нет) и много-много всего интересного, а так же анализировать ошибки, внезапно возникающие при работе.

В планах прикрутить авторизацию на основе блокчейна (воспользуюсь готовым сервисом, но главное — блокчейн антихайп), server-side рендеринг страничек полностью реализовать и сделать нормальную систему service-worker’ов, чтобы клиентская часть работала быстро в нескольких потоках (вероятно) и вообще: всё было здорово.
Но к этому я перейду после того, как сделаю базовую часть клиентской части, ибо, по сравнению с сервером, времени на это уйдёт ну очень много.

Впилил защиту от бесконечных регистраций и брутфорса паролей, ну и, конечно, закинул сбор статистики кого и с каким IP заблокировала «защита».

Ранее Ctrl + ↓