5.31.2020

Забираем вебинар

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

Как обычно в хроме нажимаем правой кнопкой мышки на видео и "посмотреть код".
Хром любезно предлагает нам ссылку на видео. Это хостинг Vimeo. Открываем ссылку на новой странице. Но нас ожидает облом:
Видео защищено по домену, с которого его пытаются запустить.
И вот тут нам помогут два плагина для хрома.

Referer Control

Referer Control подменит домен с которого мы заходим:

Simple Vimeo Downloader


А Simple Vimeo Downloader позволит скачать видео.
Вот теперь вебинары можно посмотреть в свободное время.


1.04.2020

Delphi 2020 (JSON REST API)

В приличном обществе, к которому надеюсь вы и принадлежите, упоминание Delphi исчезло около 20 лет назад.
В среде гиков, к которой вы возможно принадлежите, упоминание Delphi исчезло около 10 лет назад, когда Windows Form стали забываться, а для разработки серверных приложений, это был не самый удобный инструмент.
Да и Microsoft Visual Studio, как мне кажется, безоговорочно победил в создании корпоративных приложений.

Однако Embarcadero Technologies с завидным упорством выпускает новые и новые версии.
Нынче это RAD Studio 10.3. Поговаривают, что с помощью нее можно делать приложения для MacOS, iOS, Android и т.д.

И даже последние два года появилась лицензия Community Edition с нулевой стоимостью:
​"Лицензия на использование продолжает действовать до тех пор, пока прибыль физического лица или компании от приложений Delphi не достигнет 5 000 долларов США, или штат команды разработчиков не превысит 5 человек."
Но кому это все нужно в 2020, когда вся парадигма разработки ушла далеко вперед?

Отбросим философию. На самом деле это я с завидным упорством год от года обновляю Delphi и безмерно благодарен новым версиям, которые позволяют продлить юность (но не только по этому).

У меня есть некоторые задачи, которые требуют автоматизации в среде Windows:
- сборка прошивок, индивидуальных инсталляционных .exe пакетов;
- подписывание сборок электронной подписью;
- и еще немного, что необходимо делать в среде windows.

Раньше утилита подключалась к базе данных, брала оттуда все что нужно и записывала обновления. За последний год все проекты переползли с MSSQL на PostgreSQL. Утилита, естественно, перестала работать, руки все не доходили починить, а тут праздники.

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

То есть долой подключение к базам данных с клиента. Достаточно постучаться по URL и данные придут на клиента, достаточно постучаться по URL с параметрами и данные уйдут обновляться через сервер. Конечно это современно и технологично, да жаль опоздали лет на десять, а для кого-то и на двадцать.

Пруфы для просмотра и чтобы не забыть:
https://webdelphi.ru/2019/03/rabota-s-json-v-delphi-10-3-rio/
https://www.youtube.com/watch?v=CARIBaJL-DY




1.31.2018

Let's Encrypt через DNS



Ну и напоследок.
Если нет возможности выпустить сертификат через редирект.
А я не могу выпустить, так как у меня стоит глобальный редирект на другой сервер, в котором нет искомой папки.
То на помощь приходит верификация по DNS.
Запускам программу:    
certbot --manual --preferred-challenges dns certonly -d domain-name

Программа пошуршит и предложит нам добавить TXT запись в домен, типа:
Please deploy a DNS TXT record under the name
_acme-challenge.domain-name with the following value:

igb-Z8U5y82vqpYeCos3001Ii5uD2wyfLAhBN5ScHtA

Before continuing, verify the record is deployed.

Добавляем TXT запись в DNS, нажимаем Enter и наш сертификат выпущен! 

1.29.2018

Lets Encrypt не работает, думаете вы?


Если вы делали сертификаты с помощью Lets Encrypt, то скорее всего сделать новый сертификат у вас не получится с помощью команды:

$ sudo letsencrypt --apache -d example.com

Будет ошибка:

Client does not support any combination of challenges that will satisfy the CA.

Это происходит потому что:

You need to upgrade your Certbot. Let’s Encrypt permanently disabled the TLS-SNI-01 challenge302 due to a security report, as of 2018-01-09.

А что собственно произошло?

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

Сделаем все через certbot

Поставим certbot:

$ sudo apt-get update
$ sudo apt-get install software-properties-common
$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install python-certbot-apache

Создадим папку

В доступной для веб-сервера директории создадим отдельную папку, скажем, letsencrypt, которую затем мы будем использовать для всех обслуживаемых доменов и установим ее владельцем веб-сервер:

mkdir /var/www/letsencrypt
chown www-data:www-data /var/www/letsencrypt

Обработаем запрос

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

http://example.com/.well-known/acme-challenge
приводил к физическому размещению:

/var/www/letsencrypt/.well-known/acme-challenge
Для Apache 2.x будет выглядеть вот так: Для подготовки к работе с Certbot добавьте в основной конфигурационный файл /etc/apache2/apache2.conf следующую секцию:

Alias /.well-known/acme-challenge/ /var/www/letsencrypt/.well-known/acme-challenge/

<Directory "/var/www/letsencrypt/.well-known/acme-challenge/">
    Options None
    AllowOverride None
    ForceType text/plain
    Require all granted
    RedirectMatch 404 "^(?!/\.well-known/acme-challenge/[\w-]{43}$)"
</Directory>

Перезапускаем Apache:
sudo /etc/init.d/apache2 restart

Получение сертификата

Запрашиваем новый сертификат командой
sudo certbot --authenticator webroot --installer apache --webroot-path /usr/data/www/letsencrypt

Среди предложенных доменов выбираем нужный домен (или задаем командной -d).Выбираем необходимость редиректа с HTTP.





                                                 

12.10.2017

ffmpeg с вебкамеры

Мне нужно было записать 5 минут видео с веб-камеры и уместить его в 5 мегабайт.

До сего момента с ffmpeg я не сталкивался, поэтому попытка записать видео с камеры для последующего его просмотра из веб-браузера делалась методом гугления проб и ошибок (мы вновь говорим про Ubuntu).

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



1. Проверка камеры

Для начала воткнем камеру в usb и проверим ее наличие командой:
ls /dev/video*
Если все хорошо, то в консоль будет выдано имя камеры типа:
/dev/video0

2. Простая запись

Самый простой пример записи с камеры будет вот таким:
ffmpeg -f v4l2 -i /dev/video0 -t 10 1.mp4

где:
-f v4l2 - API видео;
-i /dev/video0 - откуда берется видеопоток;
1.mp4 - куда кладется видеопоток;
-t 10 - ограничение 10 секунд (но прервать запись можно в любой момент, нажав q).

Результат можно посмотреть в браузере.
Однако, есть несколько но:
- разрешение будет не то, которые вы ожидали;
- размер файла будет большой;
- на слабом компьютере изображение будет дергать.
- в браузере андройда вы скорее всего не увидите результат.

Давайте резберем все по очереди.

Вот что нужно запомнить: перед -i ставятся все настройки для входящего потока, после -i, для записываемого.

3. Тюнингуем

3.1. Возможности камеры

Проверим возможности камеры, выполнив команду:
ffmpeg -list_formats all -i /dev/video0

У меня выдается:
[video4linux2,v4l2 @ 0x1a74790] Raw       :     yuyv422 :           YUYV 4:2:2 : 640x480 160x120 176x144 320x176 320x240 432x240 352x288 544x288 640x360 752x416 800x448 864x480 960x544 1024x576 800x600 1184x656 960x720 1280x720 1392x768 1504x832 1600x896 1280x960 1712x960 1792x1008 1920x1080 1600x1200 2048x1536 2592x1944
[video4linux2,v4l2 @ 0x1a74790] Compressed:       mjpeg :          Motion-JPEG : 640x480 160x120 176x144 320x176 320x240 432x240 352x288 544x288 640x360 752x416 800x448 864x480 960x544 1024x576 800x600 1184x656 960x720 1280x720 1392x768 1504x832 1600x896 1280x960 1712x960 1792x1008 1920x1080 1600x1200 2048x1536 2592x1944

Из выдачи мы видим:
- поток с камеры может быть не сжатый (Raw) и сжатый (Compressed);
- разрешение с камеры может быть от 160x120 до 2592x1944.

3.2. Выбираем разрешение и входной поток

Теперь зададим параметры камеры для входящего потока, которые нас интересуют, подставив их перед -i.
Меня интересует сжатый формат 640x460. Выполним пример:
ffmpeg -f v4l2 -input_format mjpeg -video_size 640x480 -i /dev/video0 -t 10 2.mp4

где:
-input_format mjpeg - поток сжатого видео;
-video_size 640x480 - разрешение;
- остальное описано выше.

3.3. Уменьшаем выходной поток

Записанный файл из сжатого видео гораздо меньше чем из не сжатого, но все равно огромен.
Выберем кодек, которым будем сжимать видео.
Нас интересует кодек, который позволит проиграть видео в браузере с использованием HTML5.

ffmpeg -f v4l2 -input_format mjpeg -video_size 640x480 -i /dev/video0 -f mp4 -t 10 2.mp4

где:
-f mp4 - контейнер выходного видео;
- остальное описано выше.

Вот теперь файл должен заметно уменьшится и должен проигрываться из браузера, с помощью кода:
<video controls width="640" height="480" autoplay>
  <source src="http://site.ru/2.mp4" type="video/mp4">
</video>

3.4. Еще уменьшаем выходной поток


Еще уменьшить выходной поток можно с помощью понижения fps.

fps у нас - это количество кадров в секунду, стандартно их 24-25, но если видео у нас в большинстве своем статичное, можно и до 5 понизить и до 1 даже.
Обратите внимание, если компьютер слабый, то при кодировке он не сможет вытянуть 24 кадра в секунду и будет пропускать кадры, так что изображение будет дергаться неравномерно. Поэтому для слабых компьютеров понижение fps - это даже необходимость.
При чем, например входной поток не всегда можно понизить сразу, устройство может не работать с таким fps, которым вы от него хотите.
Поэтому можно понизить и входной поток до допустимо возможного, чтобы не перегружать процессор и выходной, чтобы поджать видео.

ffmpeg -f v4l2 -input_format mjpeg -video_size 640x480 -r 5 -i /dev/video0 -r 1 -f mp4 -t 10 2.mp4
где:
-r 5 - ограничение входного потока (до директивы -i) до 5 fps, дабы не грузить процессор;
-r 1 - ограничение входного потока (после директивы -i) до 1 fps, дабы поджать видео еще больше.
- остальное описано выше.

3.5. Еще уменьшаем выходной поток (альтернатива)

Альтернативно выходной поток можно понизить с помощью изменения битрейта (размера потока видео в секунду).
Забудем про пример выше (после такого уменьшения fps битрейт нам уже не поможет). Сделаем средний битрейт по размеру 100 килобит в секунду:
ffmpeg -f v4l2 -input_format mjpeg -video_size 640x480 -i /dev/video0 -b:v 100k -f mp4 -t 10 2.mp4

где:
-b:v 100k - средний битрейт 100 килобит в секунду;
- остальное описано выше.

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

Побирайте битрейт, читайте документацию про минимальный битрейт, максимальный битрейт, буфер и т.д. и т.п.

3.6. А как же браузер андройд?


На самом деле в процессе кодировки ffmpeg сам подсказывает что делать:
No pixel format specified, yuvj422p for H.264 encoding chosen.
Use -pix_fmt yuv420p for compatibility with outdated media players

Вот и добавим эту дерективу в выходной буфер:
 ffmpeg -f v4l2 -input_format mjpeg -video_size 640x480 -i /dev/video0 -vf format=yuv420p -f mp4 -t 10 2.mp4

где:
-vf format=yuv420p - формат, совместимый с медиаплеерами в сматрфонах;
- остальное описано выше.

P.S.
На сервере в .htaccess не лишне будет записать:
AddType video/mp4 .mp4 .m4v

P.S.S.
Тестируйте на динамичных изображениях. Статика будет маленькой сама по себе.

Ну вроде все для того чтобы посоревноваться в сжатии. У меня получается 5 мегабайт на 5 минут видео. А у вас?


12.06.2017

Расследование зависания cURL при передаче большого файла

Экспозиция
Потребовалось мне как-то с одного сервера на другой заливать файл размером около мегабайта. Вроде бы ничего сложного, используется библиотека cURL, которая позволяет все что хошь, какими хошь методами заливать. Мне принципиально нужен был raw файл методом POST (и да, мы говорим про Ubuntu).  Все шло как по учебнику. 

Завязка
Когда все было протестировано, скрипты уехали в продакшн на облегчённый сервер и тут-то файл перестал заливаться. Заливка отваливалась по тайм-ауту. На приемнике даже создавался файл размером 0 байт, но дальше ничего. Проблема воспроизвелась на всех облегченных серверах, кроме тестового и облегчённого сервера «на выезде». Облегченные серверы немного отличались платформами и имели одну операционку, а вот облегчённый сервер «на выезде», имел операционку другой сборки. 
Нужно было понять в чем проблема. 

Кульминация
Маленькие файлы в несколько байт заливались, проблемы начинались на килобайтах. 
Для того чтобы исключить проблему с библиотекой cURL, была попытка залить файл из консоли и... точно также заливка отваливалась по тайм-ауту. Было выкурено много манов. 

Но ведь не толко cURL умеет заливать файлы? На нем свет клином не сошёлся.
Была попытка залить файл через ssh утилитой scp. Каково же было удивление, когда файл в 600 килобайт завис на середине заливки и скорость начала падать до 0. Тут уже нужно было курить совсем другие маны. 

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

Развязка
Курение различных манов напомнило о проблеме десятилетней давности - “подбирайте MTU!”

После смены MTU с 1500 на 1400 командой:
Ifconfig eth0 mtu 1400
Данные пошли и, как мне кажется, ещё веселее, чем до этого. 

Эпилог
Вселенная интернета обширна и полна информацией, главное правильно сформулировать вопрос ко вселенной и он будет содержать не только половину ответа, но, того глядишь, и весь ответ. 



12.05.2017

Для it-шников, которые не любят магию

Как сделать из сервиса http, который висит на непонятно каком порту внутри сети, сервис с https на 443 порту, когда под рукой есть Ubuntu и Apache.



Имеем:
- сервер Windows (или нет, не важно) в DMZ с условным адресом 10.10.10.10, на котором крутится сервис http (потому что https не придумали) на условном порту 1234 (потому что порт 80 занят).

Задача:
- организовать доступ из сети интернет на этот сервис по условному адресу: https://my.service.ru

Под рукой:
- сервер в сети интернет c условным адресом 8.8.8.8 под управлением Ubuntu, на котором установлен Apache.

Понеслась:

0. На целевом сервере

0.1.

В брандмауэре сервера открываем входящий трафик на 10.10.10.10 порт 1234.
Не обязательно для всего интернета, можно для 8.8.8.8.

0.2.

Открываем на фаерволе сети входящий трафик на сервер 10.10.10.10 порт 1234, чтобы из сети интернет до него можно было добраться (соответсвенно, серверу нужно дать внешний IP, например 9.9.9.9).
Проверяем:
telnet 9.9.9.9 1234

1. Прописываем DNS

my.service.ru 9.9.9.9

2. Делаем прокси

2.1. Пишем конфигурацию сервера

Правим файл:
sudo nano /etc/apache2/sites-available/my.service.ru.conf
И пишем в него:

<VirtualHost *:80>
        ServerName my.service.ru
  <Proxy *>
    Order deny,allow
    Allow from all
  </Proxy>

  ProxyPass / http://9.9.9.9:1234
  ErrorLog /var/log/apache2/ts_error_log
  CustomLog /var/log/apache2/ts_log common
RewriteEngine on
RewriteCond %{SERVER_NAME} = my.service.ru
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]
</VirtualHost> 
Все было ради этого

2.2. Добавляем сайт и перезапускаем сервер

sudo a2ensite my.service.ru

service apache2 reload 

2.3. Добавляем доступ по https


sudo letsencrypt --apache -d my.service.ru

Все!