Создаем свой интерфейс к Голосу на HTML и JavaScript - Часть первая
Предисловие
Несколько месяцев назад я увидел статью Golos.js - легкий способ создавать приложения для GOLOS от @dark.sun Я опробовал функциональность библиотеке golos.js и мне это весьма понравилось. Однако я долго не мог отыскать описание функций API, что у меня вызывало тоску. И приходилось изучать функции "методом тыка" :p На мое счастье, я недавно увидел статьи про создание бота для голоса от автора @ontofractal Тогда я задал вопрос, автору блога, где можно найти описание данных функций. И получил, одну из редких ссылок, конечно с очень кратким, но хотя бы каким-то описанием данного API. Других руководств для разработчиков мы не видели больше - но хотя бы что-то.Само по себе API представляет модифицорованное для Голоса API Steem-a которое хранится в файле библиотечных функций на языке JavaScript.
Начнем по-порядку и рассмотрим, основные аспекты, для понимания этих непонятных слов :)
Что такое JavaScript - ECMAScript и его версия 6
Примечание: Поскольку то что я тут пишу я беру из головы, я могу где-то ошибится. Поэтому если найдете ошибку напишите пожалуйста в комментариях.
Я представляю себе расклад дел следующим образом.
Есть стандарт созданный в 1995 году под названием ECMAScript (ECMA - это еще одна организация разрабатывающая спецификации для веба. О них я рассказывал в курсе про сети).
Можно сказать, что ECMAScript - это основа (скелет) на базе которого строятся разные скриптовые языки (технологии). Наиболее интересными для нас будут JavaScript (Встроенный в браузеры) и Node.js (Серверная технология).
Таким образом ECMAScript определяет основной синтаксис - такой как формат объявления констант, переменных, функций и управляющие конструкции (условия и циклы).
Например посмотрите какой красноречивый код в статье про ботов по ссылке выше - это современная версия спецификации ES6 (хотя технически все это можно описать с помощью var и function вместо const и стрелочных функций. Но так во многом эффективнее.
Мы однако будем писать в данной лекции простой интерфейс к Голосу запускаемый из браузера.
Далее стоит рассказать с чем мы будем иметь дело в своем коде на JavaScript.
Структуры данных - JSON
ECMAScript это "скелет" всего на что навешивается "мясо" при разработке веб-технологии, такой как JavaScript.
Используя его синтаксис мы также обращаемся к объектам, то есть мы можем как бы общаться сними на языке ECMAScript - отправляя им сообщения (которые по своей сути сами тоже подобные объекты. Также можно создавать свои (пользовательские объекты).
Объекты можно рассматривать как структуру данных. То есть набор данных связанных в одно единое.
Более просто можно понять о структурах данных на примере языков HTML и XML.
Поэтому давайте их рассмотрим.
О HTML и XML
Такие файлы по сути - обычные текстовые файлы.
Однако по мимо текста в них добавляются специальные элементы разметки - теги.
Эти теги использует программа, называемая парсер, для того, чтобы при считывании создать в памяти компьютера (буфере) специальную структуру данных, к которой затем можно будет обращаться из других программ (например из того же JavaScript).
Функции
Функции в JavaScript такие же типы данных. То есть вы можете записать функцию в переменную (точнее объект - в ECMAScript всегда везде объекты, даже числа и тем более функции).
Объект хранящий текст (код) функции может входить в какую либо структуру, обычно это JSON - это встроенный в JavaScript формат для хранения стуктуризированных данных (объектов).
Кстати говоря JSON от XML и HTML отличается только видом - функционально они очень схожи. Просто к JSON нужно немного привыкнуть и вы увидите насколько он великолепен.
Объекты и DOM
Таким образом когда браузер загружает HTML страницу он в памяти компьютера создает структуру данных, которая может иметь вложенные структуры, причем многократно.
Первый (корневой такой объект называется document) - если вы внимательно посмотрите на структуру внутри любой HTML страницы, то увидите, что HTML-теги вложены, организуя древовидную структуру. Это называется дерево DOM.
Таким образом JavaScript представляет собой ECMAScript-движек и набор объектов структуры НTML-документа, с которыми мы можем взаимодействовать: добавлять, удалять, считывать значения, слушать и добавлять события...
Технически для JavaScript DOM HTML документа выглядит аналогично формату JSON.
То есть мы можем представить себе как JSON любой объект с которым намерены работать.
Пример биткойн-транзакции в JSON
{
"amount" : 0,
"fee" : 0,
"blockindex" : 179123,
"details" : [
{
"fee" : 0,
"amount" : 0.01000000,
"blockindex" : 179123,
"category" : "receive",
"confirmations" : 0,
"address" : "1APSgU92VV77GB2YMNNMMYz7Sock5gMgV1",
"txid" : "5031738bc1f797e5e0f8b782989111d75106496c5dedea50d96e2ed1dc88190d",
"block" : 1327599863,
"blockhash" : "000000000000079bae4b877ad3810f03db249a6f239c2b69c18d44c141c470ee"
},
{
"fee" : 0,
"amount" : 0.00100000,
"blockindex" : 179123,
"category" : "receive",
"confirmations" : 0,
"address" : "15CDCKBLsvX3nZ3krMYNse6FkRcuMD1rmU",
"txid" : "5031738bc1f797e5e0f8b782989111d75106496c5dedea50d96e2ed1dc88190d",
"block" : 1327599863,
"blockhash" : "000000000000079bae4b877ad3810f03db249a6f239c2b69c18d44c141c470ee"
}
],
"confirmations" : 15767,
"txid" : "5031738bc1f797e5e0f8b782989111d75106496c5dedea50d96e2ed1dc88190d",
"block" : 1327599863,
"blockhash" : "000000000000079bae4b877ad3810f03db249a6f239c2b69c18d44c141c470ee"
}
Здесь структура обозначается так "имя_объекта":"значение", где значением могут как простые данные, так и вложенные объекты. Для указания что это объект по его сторонам ставят фигурные скобки { // это объект }
Также можно в квадратных скобках указывать массив (набор данных или объектов одинакового типа) - [ // это массив ]
Мы можем загрузить этот объект в память и присвоить идентификатор, а затем обращаться к его элементам.
var transaction = { // здесь описанная выше транзакция };
И обращаться к объектам внутри этой транзакции таким вот образом:
var address = transaction.details.address;
Что сохранит в переменную address значение биткоин кошелька.
То есть мы как бы выбираем из структуры нужные нам данные, и раскладываем их по переменным, с которыми будем дальше работать.
Например мы сможем их поместить в другую структуру-транзакцию, или добавить в структуру HTML-документа. Чтобы отобразить ее динамически в браузере пользователя.
События
События - это (как можно догадаться) тоже объекты, которые генерируются автоматически при определенных обстоятельствах.
Например при клике пользователя по определенному HTML-элементу в браузере (чаще всего это кнопка или картинка).
Когда это происходит браузер генерирует объект событие и рассылает его функциям, которые это событие отслеживают (ждут). Такие функции называют listener - слушатель.
Когда функция - слушатель получает такой объект, он передается ей в через ее параметр.
А затем срабатывает сам код функции. А вот внутри этого кода мы уже выполняем наши действия, которые приводят к нужному нам результату.
Например с использованием библиотеки jQuery это может выглядеть так:
$("#my_btn").on("click", function(e){
// Здесь обработка события
});
Здесь мы ищем в структуре HTML-документа элемент (тег) с идентификатором (атрибутом id) равным my_btn, и привязываем к нему событие "click", далее мы описываем анонимную функцию, в которой выполняем нужные нам действия.
То есть каждый раз при клике по кнопки с данным идентификатором будет отрабатывать наш код описанный в теле функции.
То же самое можно написать так
$("#my_btn").on("click", myfunc);
function myfunc(e){
// код
}
или используя новинки ES6
$("#my_btn").on("click", (e) => {
// Здесь обработка события
});
Потоковые соединения - WebSocket
Веб-сокет это очень полезная вещь, когда нам нужно поддерживать потоковое соединение с сервером (а не только в формате HTTP - запрос ответ).
Таким образом данные поступают постоянно в обеих направлениях. И помечая специальными последовательностями данные приходящие в этих потоках.
Как только программа отслеживает такую строчку, то она отсылает событие. Причем в зависимости от направления потока могут происходить события как на стороне сервера, так и у клиента.
У нас есть специальная библиотека с функциями, которую мы подключим в наш тестовый html-документ. После чего, подключимся к блокчейну голоса, и начнем отслеживать события.
Итак попробуем.
Hello, Golos!
Скачиваем библиотеку golos.io по ссылке, представленной автором выше на гитхабе - https://github.com/dacom-dark-sun/golosjs/archive/dev.zip
Распаковываем архив и видим там следующие содержимое
Нам оттуда понадобится один файл, который лежит в папке dist и называется golos.min.js
Создадим у себя (например на рабочем столе) папку и назовем ее как нравится (у меня golos-test) в ней для удобства папку js - туда мы копируем файл с функциями для Голоса golos.min.js который мы взяли из скаченного дистрибутива. Затем переходим обратно в вышележащую папку (golos-test) и создаем в ней файл index.html
В созданный нами index.html копируем (или пишем) следующий код
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Golos.js</title>
</head>
<body>
<script src="js/golos.min.js"></script>
<script>
steem.api.getConfig(function(err, response){
console.log(err, response);
});
steem.api.getAccounts(['rusldv'], function(err, result) {
console.log(err, result);
});
steem.api.streamTransactions(function(err, result) {
console.log(err, result);
});
steem.api.getActiveWitnesses(function(err, result) {
console.log(err, result);
});
</script>
</body>
</html>
Это достаточно простой код создающий html-страницу для любого браузера
В заголовке страницы мы подключаем нашу библиотеку golos.min.js которую мы скопировали во вложенную папку js.
Затем мы просто вызываем функции API.
Результат работы этих функций мы выводим с помощью метода console.log()
Этот метод выводит данные в одно хитрое место в нашем браузере - в консоль разработчика :)
Открыть ее можно нажав клавишу F12 или через контекстное меню страницы в Chrome пункт меню называется "Просмотреть код".
Затем там нужно перейти на вкладку Console - в ней кстати можно даже на прямую писать и выполнять команды JavaScript и там же отображаются все ошибки локальных скриптов. Но пока что нам она нужна только для просмотра вывода функцией console.log
Это результат работы функции
steem.api.streamTransactions(function(err, result) {
console.log(err, result);
});
Эта функция подключается к сокету и каждый раз при появлении новой транзакции в блокчейне Голоса генерируется событие, которое выводит в консоль объект транзакции Голоса - то о чем мы говорили выше.
Здесь следует отметить, что сокет связывается с адресом ws.golos.io и соответствующей нодой.
Если вы захотите поднять свою собственную ноду - статьи об этом я нашел у @vik Подключаемся к ноде wss://ws.golos.io через блокнот. Подробный разбор JavaScript, общение с API golos.io, + бонус - данные аккаунтов БМ )
Еще у нас в коде были 2 функции - они события (новые транзакции) не получают, за то выводят полезную информацию.
Первая
steem.api.getConfig(function(err, response){
console.log(err, response);
});
выводит состояние работы блокчейна. Всю основную информацию о его статусе.
Ну а вторая
steem.api.getAccounts(['rusldv'], function(err, result) {
console.log(err, result);
});
как несложно догадаться информацию об аккаунте (я там свой написал, что бы убедиться что все верно :))
Квадратные скобки, обозначают что мы передаем функции массив, то есть можно перечислить много разных аккаунтов.
Таким образом мы можем получать различную информацию о всем что находится в блокчейне.
Естественно мы сможем и добавить туда данные, передав функции специальные приватные ключи аккаунта. Но это в следующих уроках.
Я немножечко изменил свой код
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Golos.js</title>
</head>
<body>
<script src="js/golos.min.js"></script>
<script>
steem.api.streamTransactions(function(err, result) {
if(err) {
document.write("Ошибка: " + err);
location.reload();
}
document.write("<br />Номер блока " + result.ref_block_num + " Время генерации " + result.expiration);
//console.log(result);
});
</script>
</body>
</html>
папку с написанным я выложил сюда
Здесь вы увидите номера и время генерации блоков элементарной функцией document.write
Конечно в реальных проектах мы будем использовать более продвинутые функции, стили и фреймворки. Однако для данного урока на этом мы остановимся.
Как с тобой связаться в рокет чате?
Окей заходу)
Круто все написал, спасибо!
И Вам спасибо)
Привет!
Этот пост был выбран Академией Голоса и попал в список программы поддержки качественных образовательных постов.
Ссылка на твой пост будет опубликована в отчете Академии.
Спасибо за полезный контент (ノ◕ヮ◕)ノ*:・゚✧
Благодарю)
А вот у меня консоль материться. Говорит невозможно связаться с такой нодой ошибка 502. Вот вывод:
WebSocket connection to 'wss://ws.golos.io/' failed: Error during WebSocket handshake: Unexpected response code: 502
(anonymous) @ golos.min.js:1
r._execute @ golos.min.js:1
o._resolveFromExecutor @ golos.min.js:2
o @ golos.min.js:2
value @ golos.min.js:1
value @ golos.min.js:1
A.(anonymous function) @ golos.min.js:1
A.(anonymous function) @ golos.min.js:1
(anonymous) @ index.html:11
index.html:12 Error: The WS connection was closed before this operation was made
at index.html:11 undefined
index.html:16 Error: The WS connection was closed before this operation was made
at index.html:11 undefined
index.html:25 Error: The WS connection was closed before this operation was made
at index.html:11 undefined
index.html:21 i {cause: Error: The WS connection was closed before this operation was made
at file:///home/wlad/LUI/inde…, isOperational: true, name: "Error", message: "The WS connection was closed before this operation was made", stack: "Error: The WS connection was closed before this op…nt:↵ at file:///home/wlad/LUI/index.html:20:11"…} undefined
golos.min.js:2 Unhandled rejection Error: The WS connection was closed before this operation was made
at Array.forEach (native)
at file:///home/wlad/LUI/index.html:11:11
F @ golos.min.js:2
S @ golos.min.js:1
x @ golos.min.js:1
r._notifyUnhandledRejection @ golos.min.js:1
(anonymous) @ golos.min.js:1
Да это вчера был сбой на маршрутизаторах. Сейчас работает?
Да. Работает.