Готовим котёнка

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

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

  • Терминалка должна работать под Linux, MacOS и Windows (WSL)
  • Она должна работать одинаково. То есть один и тот же параметр в конфиге должен приводить к одним и тем же изменениям в поведении.
  • Терминалка должна уметь в truecolor.
  • Терминалка должна уметь в шрифтовые лигатуры.

Всё остальное, типа рендеринга на GPU или особо правильной поддержке многих систем, мне было совершенно не нужно. Главное, чтобы я взял ноутбук на другой операционке и получил абсолютно тот же… сейчас это модно называть экспириенсом. Внезапно самым сложным для терминалок оказался последний пункт.

Я не понимаю, чего сложного в подобной конвертации символов -> >> <> != ? Но, например, авторы gnome terminal не осилили подобного и отмазались, что не для всех языков это может работать. Ну сделали бы не для всех…

И, внезапно, всем моим хотелкам удовлетворила только одна терминалка – kitty. Если быть до конца честным, то нет, были и другие, но они не такие гламурные. Ставить котёнка можно 100500 способами, но я предпочел через пакетный менеджер.

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

font_family Fira Code
font_size 12
cursor_shape block
cursor_shape_unfocused hollow
shell_integration no-cursor
scrollback_lines 10000
sync_to_monitor yes
remember_window_size  yes
initial_window_width  800
initial_window_height 600
include theme.conf
tab_bar_style slant
update_check_interval 0
term xterm-256color
paste_actions quote-urls-at-prompt
background_opacity 1
confirm_os_window_close 0
map super+n new_os_window_with_cwd
map super+t new_tab_with_cwd
map super+w close_os_window
map super+c copy_to_clipboard
map super+v paste_from_clipboard

Последние строчки – это дань моей лени, чтобы новые окошки открывались как на макоси. Win+n и не надо пальцы ломать об Ctrl+Shift+n . Мелочь, а удобно. Ну и файлик theme.conf, честно спертый из интернета и имитирующий тему homebrew

# Theme ported from the Mac Terminal application.

background #000000
foreground #00ff00
cursor #23ff18
selection_background #083905
color0 #000000
color8 #666666
color1 #990000
color9 #e50000
color2 #00a600
color10 #00d900
color3 #999900
color11 #e5e500
color4 #0000b2
color12 #0000ff
color5 #b200b2
color13 #e500e5
color6 #00a6b2
color14 #00e5e5
color7 #bebebe
color15 #e5e5e5
selection_foreground #e5e5e5

И вот я уже почти неделю живу на двух операционках и с одним терминалом. Нормально …

Теперь операционко-специфичные штуки.

MacOS: надо в ENV переменные добавить KITTY_CONFIG_DIRECTORY=~/.config/kitty/ , иначе котенок хз где хранит конфиги. А так все в одинаковом месте. Чтобы сменить иконку, надо ее просто рядом с конфигом положить и обозвать kitty.app.png.

Linux: чтобы сменить иконку, надо сделать desktop файл, аналогичный нижеприведенному, и положить его в .local/share/applications/ . Главная боль – путь до иконки должен быть абсолютным.

[Desktop Entry]
Version=1.0
Type=Application
Name=kitty
GenericName=Terminal emulator
Comment=Fast, feature-rich, GPU based terminal
TryExec=kitty
StartupNotify=true
Exec=kitty
Icon=/home/kiltum/.config/kitty/kitty.app

Все 🙂

Всё своё ношу с собой. Локальное зеркало.

Пора, пора описывать то, что было сделано. А то как обычно, забудется и всё, пиши “прощай”.

Итак, давным-давно, когда ещё существовала страна под названием “Украина”, я начал делать свою… Ну даже не знаю, на лабораторию это не тянет, на свой датацентр тоже. В общем, несколько серверов, выполняющих нужные для меня задачи. Часть арендованные, часть свои… И всё было совсем хорошо, пока не началась СВО. Тут же вылезла куча говна и давай блочить доступ. Следом к ним присоеденились убегуны и давай портить до чего руки дотянутся. Дескать, они все такие чувствительные, что не могут позволить такое и вааще, они только за самое хорошее! Но тут не про них, а про то, как сделать себе хорошо и нагло игнорировать подобное сейчас и в будущем.

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

Погуглив, я нашел несколько инструкций, как сделать свое зеркало. Немного потыкался в монстров типа Nexus и прочих JFrog и решил, что лучшее враг хорошего. Итак, для начала нам нужна машинка с более-менее приличным диском. Далее все просто и прямолинейно: ставим необходимое и подготавливаем структуру каталогов

apt install apache2 debmirror gnupg xz-utils rsync

mkdir -p /mirror
mkdir /mirror/debmirror
mkdir /mirror/debmirror/amd64
mkdir /mirror/debmirror/mirrorkeyring
mkdir /mirror/scripts

gpg --no-default-keyring --keyring /mirror/debmirror/mirrorkeyring/trustedkeys.gpg --import /usr/share/keyrings/ubuntu-archive-keyring.gpg

cd /var/www/html
ln -s /mirror/debmirror/amd64 ubuntu

cd /mirror/scripts

А вот теперь скрипт, который все друг у друга таскают. Я не исключение

# cat > debmirroramd64.sh 
#!/bin/bash

## Setting variables with explanations.

#
# Don't touch the user's keyring, have our own instead
#
export GNUPGHOME=/mirror/debmirror/mirrorkeyring

# Arch=         -a      # Architecture. For Ubuntu can be i386, powerpc or amd64.
# sparc, only starts in dapper, it is only the later models of sparc.
# For multiple  architecture, use ",". like "i386,amd64"

arch=amd64

# Minimum Ubuntu system requires main, restricted
# Section=      -s      # Section (One of the following - main/restricted/universe/multiverse).
# You can add extra file with $Section/debian-installer. ex: main/debian-installer,universe/debian-installer,multiverse/debian-installer,restricted/debian-installer
#
section=main,restricted,universe,multiverse

# Release=      -d      # Release of the system (, focal ), and the -updates and -security ( -backports can be added if desired)
# List of updated releases in: https://wiki.ubuntu.com/Releases
# List of sort codenames used: http://archive.ubuntu.com/ubuntu/dists/

release=noble,noble-security,noble-updates,noble-backports

# Server=       -h      # Server name, minus the protocol and the path at the end
# CHANGE "*" to equal the mirror you want to create your mirror from. au. in Australia  ca. in Canada.
# This can be found in your own /etc/apt/sources.list file, assuming you have Ubuntu installed.
#
server=ru.archive.ubuntu.com

# Dir=          -r      # Path from the main server, so http://my.web.server/$dir, Server dependant
#
inPath=/ubuntu

# Proto=        --method=       # Protocol to use for transfer (http, ftp, hftp, rsync)
# Choose one - http is most usual the service, and the service must be available on the server you point at.
# For some "rsync" may be faster.
proto=rsync

# Outpath=              # Directory to store the mirror in
# Make this a full path to where you want to mirror the material.
#
outPath=/mirror/debmirror/amd64

# By default bandwidth is not limited. Uncommend this variable and set it to the apropriate
# value in Kilobytes per second. Also don't forget to uncomment the --rsync-options line in the last section below.
bwlimit=1000

# The --nosource option only downloads debs and not deb-src's
# The --progress option shows files as they are downloaded
# --source \ in the place of --no-source \ if you want sources also.
# --nocleanup  Do not clean up the local mirror after mirroring is complete. Use this option to keep older repository
# Start script
#
debmirror       -a $arch \
                --no-source \
                -s $section \
                -h $server \
                -d $release \
                -r $inPath \
                --progress \
                --method=$proto \
                --rsync-options "-aIL --partial --bwlimit=$bwlimit" \
                $outPath

Скрипт настроен на российский миррор и лимит в 1 мегабайт в секунду, чтобы не забивать канал, как минимум при первоначальной скачке. Ну и релиз поменял на noble, ибо нынче уже 2024 год и в ходу у меня 24.04. Далее просто запускаем этот скрипт и идем заниматься своими делами. Оно медленно и печально высосет кучу гигабайт. Реально КУЧУ гигабайт. На момент написания размер зеркала был в районе двухсот гигов.

Ну а дальше просто везде разбрасываем новый ubuntu.list, заменяя им ubuntu.sources

deb http://mirror/ubuntu noble main restricted universe multiverse
deb http://mirror/ubuntu noble-security main restricted universe multiverse
deb http://mirror/ubuntu noble-updates main restricted universe multiverse

И точно так же миррорим что-то другое. К примеру, возжелал я поставить InfluxDB. Можно пакетики тащить, а можно зеркало сделать.

wget -q https://repos.influxdata.com/influxdata-archive_compat.key
gpg --no-default-keyring --keyring /mirror/debmirror/mirrorkeyring/trustedkeys.gpg --import influxdata-archive_compat.key
mkdir -p /mirror/debmirror/influx/
cat influxdata-archive_compat.key | gpg --dearmor > /mirror/debmirror/influx/key.gpg
cd /var/www/html
ln -s /mirror/debmirror/influx influx

И чуточку поправленный скрипт без комментариев. Изменил только откуда брать, куда ложить и то, что не надо использовать rsync. Адреса и прочее я нагло упер из инструкции с официальной страницы https://www.influxdata.com/downloads/, когда выбрал Ubuntu&Debian

# cat influx.sh 
#!/bin/bash

export GNUPGHOME=/mirror/debmirror/mirrorkeyring
arch=amd64
section=main
release=stable
server=repos.influxdata.com
inPath=/debian
proto=http
outPath=/mirror/debmirror/influx

debmirror       -a $arch \
                --no-source \
                -s $section \
                -h $server \
                -d $release \
                -r $inPath \
                --progress \
                --method=$proto \
                --rsync-extra=none \
                $outPath

Ну и потом на хосте, куда что-то от influx будет ставиться:

wget http://mirror.hlevnoe.lan/influx/key.gpg -O /usr/share/keyrings/influx.gpg

cat > /etc/apt/sources.list.d/influx.sources 
Types: deb
Architectures: amd64
Signed-By: /usr/share/keyrings/influx.gpg
URIs: http://mirror.hlevnoe.lan/influx
Suites: stable
Components: main

Дальше совершенно стандартно: apt update && apt install...

Умный дом. MQTT сервер

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

Исторически сложилось, что для централизации подобного используется протокол MQTT. Он легкий, простой и поддерживается всеми участвующими в деле устройствами.

Вообще у меня уже есть один mqtt сервер, встроенный в wirenboad. Но есть два больших но: 1) сам по себе wirenboard очень дохлый (хотя народ радостно на него даже Home Assistant в докере водружает) и 2) у меня будет очень много устройств, общающихся по MQTT.

Поэтому решение простое: поднимаем на виртуалке MQTT сервер и заставляем всех с ним работать. А кто не умеет или умеет не кошерно – забирать с тех данные самим. Для реально больших нагрузок или отказоустойчивости народ ставит EMQX, но у меня такого не будет, поэтому использую mosquitto.

apt install mosquitto mosquitto-clients

Все настройки оставляю по умолчанию, просто добавляю один мост wirenboard->mosquitto.

# cat /etc/mosquitto/conf.d/wirenboard.con
connection wirenboard
address wirenboard:1883
bridge_insecure true
topic # in 0

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

mosquitto_sub -t \#

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

Первая ачивка получена!

Как сбросить кеш только для одного файла

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

Небольшое расследование со службой поддержки wirenboard показало, что дело в одном маленьком файлике. Вернее с тем, как linux с ним обращается. Верхнеуровневый софт честно в него пишет нужное, а вот линукс, желая сберечь ресурс emmc, начинает активно кешировать и сбрасывает файловый кеш тогда, когда в 99% уже поздно.

Казалось бы, фигня вопрос: засунь в крон sync и дело в шляпе. Ок, не в крон, это перебор, а после inotify и всё. Но сбрасывать всю FS ради одного файла… В общем, рецепт ниже.

# cat /etc/systemd/system/libwbmqtt-saver.service 
[Unit]
Description=Drop file cache for libwbmqtt.db if it changed

[Service]
ExecStart=/bin/bash -c 'inotifywait -qq -e modify /var/lib/wb-mqtt-gpio/libwbmqtt.db && dd of=/var/lib/wb-mqtt-gpio/libwbmqtt.db oflag=nocache conv=notrunc,fdatasync count=0 status=none'
Restart=always

[Install]
WantedBy=multi-user.target

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

В общем, жужжит как надо.