Я подумал, что забавным побочным проектом будет создание настольного приложения, которое запускается в системном трее и отображает рыночную цену ETH в долларах США, когда вы наводите на него курсор. Следите за новостями, и я покажу вам, как я создал это простое настольное приложение.

Просто установите

Если вы хотите просто запустить это приложение, а не изучать, как оно устроено, просто выполните следующие действия:

  1. Установите git и Node.js
  2. Выполнить git clone https://github.com/travishorn/ethtray
  3. Беги npm install
  4. Беги npm start

Найдите значок Ethereum на панели задач. Наведите на него курсор мыши, чтобы увидеть рыночную цену в долларах США. Щелкните правой кнопкой мыши, чтобы вызвать контекстное меню. Выберите Обновить, чтобы запросить новую текущую цену. Выберите Выход, чтобы выйти из приложения.

Давайте построим это

Начните с создания нового каталога для нашего проекта и инициализации в нем модуля npm.

> mkdir ethtray
> cd ethtray
> npm init -y

Мы собираемся использовать несколько пакетов npm, которые уже созданы для нас другими. А именно:

  • Электрон — компоненты Menu и Tray будут очень полезны при создании приложения, работающего в системном трее.
  • Момент — отлично подходит для форматирования даты и времени.
  • Запрос — самый популярный пакет для создания и обработки HTTP-запросов.

Установите и сохраните их в пакете npm.

> npm install --save electron moment request

Наше приложение довольно маленькое. Мы можем уместить его в один файл. Создайте новый файл с именем index.js.

Внутри этого файла давайте настроим переменные и пакеты, которые нам понадобятся позже. Получите экземпляр компонентов app, Menu и Tray из Electron. Затем втяните request и moment. Мы также создадим переменную tray для хранения нашего компонента в трее. Мы хотим, чтобы эта переменная находилась в области верхнего уровня, чтобы мы могли ссылаться на нее в любой момент жизненного цикла нашего приложения.

const { app, Menu, Tray } = require('electron');
const request = require('request');
const moment = require('moment');
let tray = null;

Когда скрипт запустится, Electron запустит файл app. Мы можем прослушать событие ready и создать остальную часть приложения.

app.on('ready', () => {
  // All the remaining code will go here
});

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

tray = new Tray('ethereum-logo.ico');
tray.setToolTip('Getting market price...');
tray.setContextMenu(contextMenu);

Первая строка создает трей. Конструктор Tray принимает строку, указывающую на файл значка. Я просто использую логотип Ethereum для моего значка. Убедитесь, что он находится в том же каталоге, что и index.js, или что вы используете правильный путь при создании лотка.

Следующая строка устанавливает всплывающую подсказку. Это текст, который будет показан пользователю при наведении курсора мыши. На данный момент он просто скажет «Получение рыночной цены…». Мы обновим его, как только цена будет собрана.

Последняя строка устанавливает контекстное меню. Это меню, которое появляется, когда пользователь щелкает правой кнопкой мыши значок. Но мы передаем переменную, которой еще не существует! Давайте создадим эту переменную. Это должен быть экземпляр Electron.Menu. Объявления переменных необходимо размещать перед любой частью кода, в которой они используются. Это означает, что я напишу следующие несколько строк кода выше tray.setContextMenu(contextMenu).

const contextMenu = Menu.buildFromTemplate([
  { label: 'Update', click: updatePrice },
  { label: 'Quit', click: () => { app.quit(); } },
]);

Мы используем функцию buildFromTemplate() Menu для создания меню. Он принимает массив объектов, определяющих пункты меню. Вы увидите два пункта меню: Обновить и Выйти. Слово Выход говорит само за себя. Он вызывает app.quit() по щелчку, который закрывает приложение. Update вызывает updatePrice() по клику, который мы еще не написали. Напишем сейчас. Опять же, эти строки должны быть написаны над, где это вызывается.

const updatePrice = () => {
  // Request price and set tooltip
};

Внутри этой функции будет одна команда: запрос к Coinbase’s API рыночной цены ETH в долларах США. Обратите внимание, что для Coinbase требуется заголовок CB-VERSION, в котором указывается дата, когда вы написали свое приложение. Это гарантирует, что API всегда будет реагировать так, как ожидает ваше приложение.

request({
  url: 'https://api.coinbase.com/v2/prices/ETH-USD/spot',
  headers: { 'CB-VERSION': '2017-08-04' },
}, (err, res, body) = > {
  // Do something with the response
});

Итак, как нам обрабатывать ответ от API Coinbase? Сначала мы проверяем наличие ошибки и уведомляем нашего пользователя. Мы могли бы получить подробную информацию, посмотрев на объект err и по-разному обработав различные ошибки. Но пока я просто покажу простое сообщение об ошибке.

if (err) {
  tray.setTooltip('Error getting market price.');
} else {
  // No error. Price is in the response body
}

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

{ "data":
  {
    "amount": "300.71",
    "currency":"USD"
  }
}

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

const amount = JSON.parse(body).data.amount;
const timestamp = moment().format('YYYY-MM-DD HH:mm');

Теперь установите всплывающую подсказку.

tray.setToolTip(`$${amount} as of ${timestamp}`);

Итак, теперь у нас есть значок на панели задач, который отображает меню при щелчке правой кнопкой мыши. В меню можно обновить цену и выйти из приложения. Осталось только убедиться, что цена обновится, как только заявка будет готова. Для этого вам просто нужно вызвать функцию updatePrice() внизу события app.on('ready').

updatePrice();

Все приложение состоит из 36 строк:

const { app, Menu, Tray } = require('electron');
const request = require('request');
const moment = require('moment');
let tray = null;
app.on('ready', () => {
  const updatePrice = () => {
    request({
      url: 'https://api.coinbase.com/v2/prices/ETH-USD/spot',
      headers: { 'CB-VERSION': '2017-08-04' },
    }, (err, res, body) => {
      if (err) {
        tray.setToolTip('Error getting market price.');
      } else {
        const amount = JSON.parse(body).data.amount;
        const timestamp = moment().format('YYYY-MM-DD HH:mm');
        tray.setToolTip(`$${amount} as of ${timestamp}`);
      }
    });
  };
  const contextMenu = Menu.buildFromTemplate([
    { label: 'Update', click: updatePrice },
    { label: 'Quit', click: () => { app.quit(); } },
  ]);
  tray = new Tray('ethereum-logo.ico');
  tray.setToolTip('Getting market price...');
  tray.setContextMenu(contextMenu);
  updatePrice();
});

Приложение можно запустить, вызвав node_modules\.bin\electron . (точка в конце важна).

Мы можем сократить это, добавив скрипт в packages.json:

"scripts": {
    "start": "electron ."
  },

После этого вы можете запустить приложение, запустив npm start.

Весь код (и не только) доступен в этом репозитории GitHub.