Здесь, в Infinite Red, мы проводим много видеоконференций! Почему? Потому что все живут и работают в разных местах! Мы совершенно удаленная компания. Мы используем услугу видеоконференцсвязи Zoom, чтобы оставаться на связи с коллегами и клиентами.
С Zoom у вас могут быть постоянные места для онлайн-встреч, называемые комнатами, каждая со своим постоянным URL-адресом. Эти URL-адреса запомнить непросто, поэтому мы создали инструмент браузера для подключения к этим комнатам. В инструменте браузера каждой комнате дается псевдоним (например, «Клен»), и когда вы нажимаете на псевдоним, вы подключаетесь к соответствующей комнате.
Это прекрасно работает: когда мы хотим с кем-нибудь пообщаться в видеочате, мы говорим: Давай встретимся в Maple, и они открывают инструмент браузера, нажимают на Maple и пуф! Вы вместе на встрече. Но некоторым людям (например, мне) нравится делать все из командной строки; это быстрее! Поэтому я решил создать CLI (интерфейс командной строки), чтобы перенести функциональность псевдонимов инструмента браузера в командную строку. Я использовал Gluegun для создания этого инструмента, который я назвал Leaf CLI. (Кстати, мы также использовали Gluegun для создания Ignite!) В этой статье я объясню, как мне это удалось.
Настройка
Для начала я создал новый проект npm с npm init
. Затем я добавил Gluegun с npm i gluegun --save
. Затем в моем index.js
я требую, создаю экземпляр и запускаю Gluegun:
module.exports = async function () { const { build } = require(‘gluegun’) const runtime = build() .brand(‘leaf_plugin’) .loadDefault(`${__dirname}/plugins/leaf_plugin`) .createRuntime() const result = await runtime.run() }
Вы могли заметить, что здесь используется более старая версия EcmaScript. Это потому, что Node не поддерживает последнюю передовую версию ES2016. Вместо import
мы используем require
, а вместо export default
мы используемmodule.exports = <the exported async function>
.
Метод build
в Gluegun создает для нас среду выполнения. В нем есть множество методов, которые вы используете для настройки своего интерфейса командной строки. Здесь я использовал loadDefault
для загрузки моего плагина: leaf_plugin
. Я мог бы назвать это leaf_cli
, чтобы оно соответствовало названию проекта npm, но меня сбивает с толку, когда у всех есть общие имена, и plugin
в любом случае более точен, поскольку сам по себе не является рабочим интерфейсом командной строки.
loadDefault
делает leaf_plugin
и все его команды доступными в CLI. Если вы включаете несколько плагинов, вы можете загрузить не более одного с помощью loadDefault
, а остальные должны быть загружены с помощью load
. loadDefault
сообщает вашему интерфейсу командной строки предположить, что вы хотите использовать этот плагин, если не указан другой. Также есть loadAll
и некоторые параметры, которые вы можете использовать для управления загружаемыми плагинами, но я не буду здесь останавливаться на них.
Плагины
Настроив CLI и включив мой плагин, пришло время добавить несколько команд в мой плагин. Команды помещаются в ./commands
каталог папки плагина. В данном случае это ./plugins/leaf_plugin/commands/
. В структуре каталогов плагинов leaf_cli
это даст мне команды invite
, join
, list
, reserve
и setName
. nameConfig.js
и roomIds.js
- служебные файлы.
. └── plugins └── leaf_plugin ├── checkRoom.js ├── commands │ ├── invite.js │ ├── join.js │ ├── list.js │ ├── reserve.js │ ├── rooms.js │ └── setName.js ├── nameConfig.js └── roomIds.js
Для каждого дополнительного плагина вы добавляете каталог (имя которого совпадает с именем плагина), содержащий другой каталог с именем commands
, в который вы помещаете свои команды. Обратите внимание, что если вы создаете интерфейс командной строки с одним плагином, вам не нужно включать plugins
каталоги с названиями (например ,leaf_plugin
). Вместо этого вы можете поместить commands
в корень вашего проекта. Я мог бы сделать это с помощью Leaf CLI, но я хотел проиллюстрировать более общий подход.
Первая команда, которую я написал, была join
; давай взглянем на это. Вот команда
целиком, но я тоже разбиваю ее по частям:
module.exports = async function (context) {
const { print, http, system, parameters } = context
const { info, warning, success } = print
const { getAndSetName, nameFromConfig } =
require(‘./../nameConfig’)
const { roomIds } = require(‘./../roomIds’)
room = parameters.second
user = parameters.third
if (user==null && nameFromConfig(context)==null) {
await getAndSetName(context)
}
name = nameFromConfig(context)
const roomId = roomIds[room]
if (roomId != null) {
const api = http.create({
baseURL: “http://leaf.infinite.red”,
headers: {‘Accept’: ‘text/html’},
maxRedirects: 0
})
const request = ‘/join/’ + room + ‘/’ + name
const response = await api.get(request)
system.run(“open zoommtg://zoom.us/join?confno=” + roomId)
} else {
warning(“That’s not a valid room”)
}
}
А теперь давайте разберемся:
const { print, http, system, parameters } = context
Сначала я извлекаю некоторые инструменты из context
, которые Gluegun предоставляет для подключаемых
команд. context
набита вкусностями, как сказал бы его автор Стив Келлок. Эти полезности включают в себя набор сторонних библиотек, которые предлагают широко применимые общие функции, такие как работа с файлами, взаимодействие с API, аргументы и подсказки командной строки. Мы скоро увидим, как некоторые из них используются в команде join
.
room = parameters.second user = parameters.third
Затем я беру аргументы командной строки, используя parameters
, одно из свойств, предоставляемых Gluegun. Синтаксис join
: leaf join <room> <user>
.
const { getAndSetName, nameFromConfig } = require(‘./../nameConfig’) // … if (user==null && nameFromConfig(context)==null) { await getAndSetName(context) } name = nameFromConfig(context)
Здесь я использую один из файлов служебных программ, о которых упоминал ранее, чтобы получить имя пользователя. Leaf CLI сохраняет имя пользователя как конфигурацию, поэтому он проверяет аргумент командной строки
и файл конфигурации для него. Если имя пользователя не еще сохранено, функция getAndSetName(context)
запросит его у пользователя. Я передаю context
, потому что он содержит стороннюю библиотеку, которую я буду использовать для подсказки. Заглянем внутрь nameConfig.js
, чтобы увидеть, как это работает.
// nameConfig.js const getAndSetName = async function(context) { const { prompt } = context prompt.question(‘name’, ‘What is your name?’) return prompt.ask(‘name’) .then(function(answer){ setName(context, answer.name) }) }
Как видите, я извлекаю prompt
из context
, а затем использую его, чтобы запросить
имя пользователя. setName
делает то, что написано на жестяной коробке. Мы не пойдем дальше именно в эту кроличью нору; назад к join.js
!
// ... const api = http.create({ baseURL: “REDACTED”, headers: {‘Accept’: ‘text/html’}, maxRedirects: 0 }) const request = ‘/join/’ + room + ‘/’ + name const response = await api.get(request) system.run(“open zoommtg://zoom.us/join?confno=” + roomId) // ...
После проверки room
аргумента командной строки мы используем еще одну полезность из context
, http
от Gluegun, чтобы сделать http-запрос. Этот конкретный запрос обновляет версию Leaf для браузера, чтобы показать присутствие пользователя. Наконец, мы воспользуемся последним плюсом Gluegun, system
, чтобы открыть приложение Zoom и присоединиться к комнате.
Вот как это выглядит в действии:
Заключение
Это охватывает основы Gluegun! Это позволяет безболезненно создавать новые интерфейсы командной строки с использованием существующих плагинов. Сообщите нам, если вы сочтете это полезным в ваших собственных интерфейсах командной строки!
О Моргане
Морган - инженер-программист, специализирующийся на веб-проектах в Infinite Red. Ей нравится использовать Rails и Phoenix. Следующие посты Моргана вы можете увидеть в Публикации Red Shift. Следить за ней можно на Medium и GitHub.