Telegram CLI - обёртка для демона под zsh

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

Коротко о zsh

Если вы всё ещё используете bash, то пришло время поменять его на zsh. Так надо.

Функция или отдельный файл?

Кому как удобнее; можете создать файл где-нибудь в путях и писать функционал в нём. Лично я храню все функции кучей в ~/.zshrc. Поэтому описывать буду именно работу с функцией.

Для начала напишем простейшую оболочку:

function tcli () {
  if [ $# -lt 1 ]; then
    nc localhost 7313
    return 0
  fi

  echo "$@" | nc localhost 7313
}

Не забываем перезайти в zsh, чтобы изменения вступили в силу!

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

tcli help

Получаем:

Проблемы?

Молчание было ей ответом

Да, тут есть пара проблем. Одну из них вы заметите, когда попробуете написать какую-нибудь команду, от которой ответ придёт не моментально. Например, dialog_list. Netcat отправит команду и тут же закроет соединение, не дождавшись ответа. Печально.

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

Мы будем слать команду на демона через netcat и будем ждать пол секунды, чтобы получить ответ. Так себе решение, если у вас есть вариант лучше, feel free запостить его в комменты, буду благодарен!

Изменим часть с echo на такую:

(echo "$@"; sleep 0.5) | nc localhost 7313

Теперь dialog_list радостно отвечает нам списком диалогов! А потом жадно жрёт процессорное время ещё треть секунды - какое расточительство!

Абсолютная и относительная власть

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

  • Открыть терминал
  • tar‘нуть или mysqldump‘нуть что-нибудь
  • Запустить клиент Telegram‘a
  • Открыть Nautilus
  • Переместить руку с клавиатуры на мышку
  • Найти нужный файл в проводнике
  • Схватить его мышкой
  • Alt+TAB‘нуться на Telegram
  • Перетащить файл на нужный контакт

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

Как я делаю это сейчас?

  • Открываю терминал
  • Делаю дамп
  • tcli send_file КОНТАКТ ФАЙЛ

Но с существующей обёрткой у нас так пока сделать не получится, ещё не поняли почему?

Про власть в заголовке было так, для красивого словца, на самом деле здесь речь пойдёт о путях. Наш демон работает из /opt/tg/bin, а рабочая директория терминала у нас может быть где угодно, поэтому когда мы хотим отправить файл, telegram-cli будет искать его относительно своего bin‘a, а не относительно пути из нашего терминала.

Конечно, можно каждый раз скармливать ему абсолютный пусть до отправляемого файла, но мы тут говорим об удобстве, а добавлять `pwd` к файлу это не то что не очень удобно, это очень неудобно. Проблему надо как-то решать! Запаситесь костылями терпением, остался последний рывок.

Вставим в нашу функцию такой кусок:

tmpargs=()
for var in "$@";do
  if [[ -f $var ]]; then
    var=`realpath $var`
  fi
  tmpargs+=($var)
done

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

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

Как изменять аргументы напрямую в массиве переданных аргументов я не знаю(если вы знаете как, то welcom в комменты), поэтому мы создадим временный массив, в которым будет результирующий массив; он же и пойдёт к демону.

Итоговая функция теперь выглядит так:

function tcli () {
  if [ $# -lt 1 ]; then
    nc localhost 7313
    return 0
  fi

  tmpargs=()
  for var in "$@"; do
      if [[ -f $var ]]; then
        var=`realpath $var`
      fi
      tmpargs+=($var)
  done

  (echo "$tmpargs"; sleep 0.5) | nc localhost 7313
}

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

Это всё?

На сегодня хватит. Я думал здесь же написать про автодополнение по tab‘у, но статья и так получилось массивной, так что об этом в следующий раз.
Спасибо, что читаете!