[О блоге] [наверх] [пред] [2023-03-11 19:49:56+03:00] [66a73601f697c99ce2d0554eebe5017e2a0861bd]

Заменил matterircd на самописный mmc

http://www.mmc.stargrave.org/
На работе для IM-а используется Mattermost. Это у которого в РФ даже
сайте нельзя открыть. И клиентов для него никаких нет толковых для
терминала. По сути только один официально есть, но написанный на
Haskell. Я честно искал как этот Haskell можно бы было собрать без
бинарников из Интернета. Штатно разработчики GHC ничего не предлагают.

Штатные клиенты это сплошной GUI или мобильные приложения или нечто
запускаемое в броузере. Когда-то MM у меня в jail-е с Firefox-ом
отображался. Но после очередного обновления сервера -- перестал
полностью. Короче ничего адекватного.

Поэтому я использовал единственное что вообще хоть как-то что-то с ним
позволяло делать: matterircd, который эмулировал IRC сервер и был неким
мостом между IRC клиентом и MM-сервером.

Из-за IRC природы, длинные сообщения бьются на части. Нередко
отправляется сообщение в котором только одно слово остаётся.
Многострочные сообщения не отправить вовсе. В качестве клиента использую
irssi, в котором нет ни vi-режима редактирования текста, ни возможности
использования внешнего редактора. В общем-то это наверное намекает на
то, что это для быстрого общения и коротких сообщений. matterircd
непонятно пытается подкачивать сообщения пока мы были в offline: что-то
месяцами прилетает каждый раз после входа, а что-то только честно один
раз.

В общем, решил рискнуть и попробовать написать свой клиент, ведь MM
написан на Go и весь его API доступен через библиотечные вызовы.
Скептически был настроен: наверняка будет много подвохов, затык в UI
обязательно небось случится, да и вообще я сам не знаю какой IM-клиент я
бы хотел видеть. Но в итоге, потратив день, удалось в общем и целом
довести его до конца. Сейчас у меня по сути нет никаких TODO которые бы
я хотел сделать.

Была идея сделать мост между XMPP клиентом и MM-сервером. Ибо уже не
будет ограничений на размеры сообщений, да и вообще даже можно было бы и
файлы передавать через этот протокол. А XMPP клиентов не мало написано.
Но когда вновь посмотрел на MCabber, который много лет когда-то
использовал, то понял что например кусок кода уже не выделить легко и
удобно из-за roster-панельки.

Иметь все сообщения сливаемые на одном экране, как это было в GNU
Freetalk, (вроде бы) mICQ, Go-шном xmpp-client или как некоторые
прадлагают для suckless IRC клиентов сливать все выводы FIFO в один
multitail -- мне точно не нравится. Вообще не шибко то много на работе
общения происходит, тем более параллельно, но не забуду как ужасно
бывает отправить сообщение не в тот чат. Я убеждён что на экране должен
быть только один чат и ввод сообщений только в него должен идти.

Suckless подход к чатикам, когда для каждого канала создаётся директория
с текстовыми файлами информационными и парой in/out FIFO файлов, из
которых можно читать приходящие сообщения и отправлять -- мне не
нравилась. Конечно же она очень проста и красива для backend-а. Но вот
frontend то удобный поверх всех этих FIFO файлов то кто будет писать?

Всегда конечно есть вариант написания просто TUI интерфейса используя
curses-like библиотеки (для Go есть раздолье). Обнаружил что для
Multitail нигде нет документации о его keybinding-ах, которые вообще
чуть ли не на каждой клавише что-то делают. Крайне разочаровал он меня
этим. Ибо были мысли о попытке его использовать для отображения нужных
мне окон.

Ещё не понимая как пойдёт написание frontend-а, я реализовал suckless
подход. Только кроме FIFO файла для входящих сообщений, я сделал просто
append-only файл. Мне в любом случае нужно сохранять
сообщения на диске, поэтому зачем заставлять делал некий tee над ним,
чтобы просто копию данных лить в файл? Но сообщения из MM могут быть
многострочными и имеют метаинформацию (как минимум postId, кроме времени
и отправителя). Сохранять его одной строкой, а потом болезненно парсить,
не охота. Поэтому делаю .rec-файл, прекрасно для этой задачи подходящий.

Приятная бага нашлась в rlwrap утилите. Читать сообщения построчно (и
отправлять построчно) -- не вариант, ибо это будет не многострочное
сообщение, а много однострочных. Сигналом завершения сообщения можно
считать закрытие FIFO файла. В rlwrap есть --one-shot опция, которая,
судя по документации, завершает выполнения после чтения первой строчки
ввода. Но если ввод был произведён --multi-line-ом, то он успешно
съедает весь введённый текст, что логично и мне понятно как
программисту. Просто это бага в документации. Бесконечный цикл с
rlwrap -o -m cat > chans/foobar/in отлично выполняет задачу. Теперь ввод
можно делать и в vi-режиме и вообще вызывать внешний редактор.

Для отображения .rec-файлов написал утилитку которая выводит одно
сообщение одной строкой (не считая многострочных), без метаинформации.
При запуске она парсит весь файл и выводить только n-последних
сообщений, эмулируя показ истории. А дальше она не закрывает файл, а
ведёт себя как tail -f, отображая появляющиеся новые сообщения. Пока
правда просто циклом со sleep-ом и проверкой размера. И выводит с каждым
сообщением и bell, чтобы оповестить tmux и терминал.

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

В общем, запускается tmux, внутри mmc, который при запуске у сервера
запрашивает и всех пользователей и каналов и у каждого канала ещё
запрашивает историю с последнего нам известного postId. Если появляются
сообщения, то он дёргает утилиту которая открывает окно в tmux, где и
утилита для чтения .rec-а и утилита для записи сообщения сразу же
запущены. Отдельный keybinding есть чтобы запустить fzf с выбором
пользователя/канала и открыть окно.

Прикреплённые файлы показываются в виде "[FILE] FileId (FileName)"
сообщения. Скачать можно послав FileId в file/get FIFO и читая его из
file/out при этом. Решил засовывать его в pax архив, где заданы поля с
FileId и MIME-типом присланным из сервера. Архив приятен тем, что в нём
имя файла чётко сохраняется. Чтобы не делать это совсем уж руками, есть
cmd/download утилитка, которой надо указать state-директорию и FileId
просто навсего. Отправку файлов думал делать через тоже посылку
сообщения в FIFO файл соответствующей users/chans директории, но пока
остановился на посылке просто сообщения "/FILE /path/to/file" прямо в
чатике.

Узнать email/имя пользователя можно прочитав users/USER/{email,name}.
Узнать его актуальный статус (online/away/offline) прочитав "status"
FIFO в нём. Аналогично информация и в каналах записывается. "users" FIFO
показывает актуальный (честно делается запрос без кэширования) список
пользователей канала. Это всё не интегрировано в tmux или какие-то
keybinding-и, ибо крайне редко требуется -- можно и руками. А оповещения
о том что пользователь что-то вводит выводятся просто делая
display-message в tmux-е, который, как этого и хотелось бы, показывается
небольшое время только.

Пока более чем доволен результатом. Оно стало значительно удобнее чем
было с irssi+matterircd. Плюс ещё и с нормальной machine-readable БД
сообщений. И возможностью отправки файлов и более удобного приёма.

    [оставить комментарий]