// import {HubConnection} from '@aspnet/signalr-client';
import { HubConnectionBuilder, LogLevel } from '@aspnet/signalr';
import Manager from "./manager";
import Visitor from "./visitor";
import Message from "./message";
import Chatroom from "./chatroom";
import ChatroomMember from "./chatroomMember";
import lzString from "lz-string";
import axios from "axios";
// const API_URL = process.env.API_URL + ':' + process.env.API_PORT + '/' + process.env.API_PATH;
const API_URL = 'https://beta.chatix.io:5022/v1';
/**
* @class Connection implements Chatix protocol implementation.
* This class is private and is used inside ChatixCore.
* @property {Function} onCOnnected
* @property {Function} onDisconnected
* @property {Function} onApplyErrorMessage
* @property {Function} onApplyDialogMessage
*/
class Connection {
/**
* Connection constructor
*/
constructor() {
this.onConnected = function(){};
this.onDisconnected = function(){};
this.onApplyErrorMessage = function(){};
/**
* @todo ждем исправления на бэкенде
*/
//this.onChatMessageError = function(){};
this.onInvalidVisitorIdConnected = function(){};
this.onApplyDialogMessage = function(){};
this.onConnectManagerToConversation = function(){};
this.onDisconnectManagerFromConversation = function(){};
this.onScreencastRequested = function(){};
this.onConnectManagerToScreencast = function(){};
this.onDisconnectManagerFromScreencast = function(){};
this.onScreenDataRequested = function(){};
this.onManagerSentScreenEvent = function(){};
this.onConnectManagerToChatroom = function(){};
this.onDisonnectManagerFromChatroom = function(){};
this.onConnectVisitorToChatroom = function(){};
this.onDisconnectVisitorFromChatroom = function(){};
this.onCreateChatroom = function(){};
this.onUpdateChatroom = function(){};
this.onDeleteChatroom = function(){};
this.onRestoreChatroom = function(){};
this.onUpdateConversationMessage = function(){};
this.onDeleteConversationMessage = function(){};
}
/**
* Starts connection
*
* @param {string} websiteId Website ID from Chatix Dashboard
* @param {string} visitorId Visitor ID that will be used to connect.
* If it is invalid, it will be replaced with new one.
* @returns {Promise<void>}
*/
async start(websiteId, visitorId) {
let hubUrl = API_URL + '/chat' + '?visitorId=' + visitorId + '&websiteId=' + websiteId;
this.hubConnection = new HubConnectionBuilder()
.withUrl(hubUrl)
.configureLogging(LogLevel.Error)
.build();
this.hubConnection.serverTimeoutInMilliseconds = 1000 * 1000 * 1000;
this.hubConnection.on('ApplyErrorMessage', (message, method) => {
this.onApplyErrorMessage(message, method);
});
/**
* @todo ждем исправления метода ChatroomMessageEror
*/
// this.hubConnection.on('ChatMessageError', (descr) => {
// this.onChatMessageError(descr);
// });
// // если уже есть ошибка связанная с неправильным visitorId
// if (!localStorage.getItem('visitorId_invalid_error')) {
// localStorage.setItem('visitorId_invalid_error', true);
// .then((res) => {
// if (localStorage.getItem('chatix__visitorId_v0')) {
// localStorage.removeItem('chatix__visitorId_v0')
// }
// localStorage.setItem('chatix__visitorId_v1', res.data);
// hubUrl = API_URL + '/chat' + '?visitorId=' + res.data + '&websiteId=' + thiss.websiteId;
// thiss.hubConnection = new HubConnectionBuilder()
// .withUrl(hubUrl)
// .configureLogging(LogLevel.None)
// .build();
// thiss.hubConnection.stop();
// localStorage.removeItem('visitorId_invalid_error');
// }
// );
// }
// else {
// // console.log('ОШИБКА ' + message + ' В МЕТОДЕ ' + method);
// }
this.hubConnection.on('OnInvalidVisitorIdConnected', () => {
this.onInvalidVisitorIdConnected();
});
this.hubConnection.on("ApplyMessage", (data) => {
this.onApplyDialogMessage(Message.buildFromInfo(data));
// разворачиваем виджет при входящем сообщении
/**
* @todo почему Connection занимается HTML деревом?
*/
// document.querySelectorAll('.chatixWindow')[0].style.bottom = 0 + 'px';
});
this.hubConnection.on("OnConnectManagerToConversation", (manager) => {
let m = Manager.buildFromInfo(manager);
this.onConnectManagerToConversation(m);
});
this.hubConnection.on("OnDisconnectManagerFromConversation", (manager) => {
let m = Manager.buildFromInfo(manager);
this.onDisconnectManagerToConversation(m);
});
this.hubConnection.on("OnRequestScreenCast", () => {
/**
* @todo почистить этот блок
*/
// // console.log('Запрос на просмотр экрана');
// // если браузер edge, то отправляем менеджеру инфу что трансляция невозможна
// if (document.documentMode || /Edge/.test(navigator.userAgent)) {
// // console.log('bad browser');
// this.hubConnection.invoke('AllowScreenCast', false).then(function () { });
// }
// else {
// this.chat.onRequestScreenCast();
// }
this.onScreencastRequested();
});
this.hubConnection.on("OnConnectManagerToScreencast", (manager) => {
let m = Manager.buildFromInfo(manager);
this.onConnectManagerToScreencast(m);
});
/**
* @todo проверить аргументы callback
*/
this.hubConnection.on("OnDisconnectManagerFromScreenCast", (manager) => {
let m = Manager.buildFromInfo(manager);
this.onDisconnectManagerFromScreencast(m);
// console.log('Менеджер отключился от трансляции');
//this.chat.onDisconnectManagerFromScreenCast();
// slideWidget();
});
/**
* @todo перенести логику обработки из Connection
*/
this.hubConnection.on("OnGetScreenData", () => {
// localStorage.setItem('screenBroadcast', true);
// // console.log('Отправляем базовую информацию');
// // создаем новый div с копией innerHTML для того, что бы в нем скрыть не транслируемые эллементы не затрагивая основную страницу
// let correctHTML = document.getElementsByTagName('html')[0].cloneNode(true);
// let scrolledElems = [];
// // console.log(correctHTML);
// document.querySelectorAll('*').forEach(function (item, i) {
// // находим все эллементы с не транслируемым классом
// if (item.classList.contains('ym-disable-keys')) {
// if (item.nodeName.toLowerCase() === 'input') {
// // IE Браузеры и Edge не корректно работают с evlutr если в начале xPath нет html
// let relativePath;
// // Если edge браузер
// if (document.documentMode || /Edge/.test(navigator.userAgent)) {
// relativePath = getDomPath(item);
// }
// else {
// relativePath = getDomPath(item).split('/');
// relativePath = relativePath.slice(2);
// relativePath = '/' + relativePath.join('/');
// }
// let hiddenElem = document.evaluate(relativePath, correctHTML, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
// hiddenElem.setAttribute('value', 'Содержимое поля недоступно');
// }
// else {
// // IE Браузеры и Edge не корректно работают с evlutr если в начале xPath нет html
// let relativePath;
// // Если edge браузер
// if (document.documentMode || /Edge/.test(navigator.userAgent)) {
// relativePath = getDomPath(item);
// }
// else {
// relativePath = getDomPath(item).split('/');
// relativePath = relativePath.slice(2);
// relativePath = '/' + relativePath.join('/');
// }
// let subElem = "<div style='width:" + item.offsetWidth + "px; height:" + item.offsetHeight + "px; background: url(https://223421.selcdn.ru/chatix-dev/assets/img/chatix_hidden_elem.png);'></div>";
// let hiddenElem = document.evaluate(relativePath, correctHTML, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
// // hiddenElem.remove();
// hiddenElem.innerHTML = subElem;
// }
// }
// // находим все поля с паролем что бы скрыть их от трансляции
// else if (item.getAttribute('type') === 'password') {
// // IE Браузеры и Edge не корректно работают с evlutr если в начале xPath нет html
// let relativePath;
// // Если edge браузер
// if (document.documentMode || /Edge/.test(navigator.userAgent)) {
// relativePath = getDomPath(item);
// }
// else {
// relativePath = getDomPath(item).split('/');
// relativePath = relativePath.slice(2);
// relativePath = '/' + relativePath.join('/');
// }
// let hiddenElem = document.evaluate(relativePath, correctHTML, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
// hiddenElem.setAttribute('value', 'Содержимое поля недоступно');
// }
// // находим все элементы со скроллом отличным от 0 в момент начала трансляции
// if (item.scrollTop || item.scrollLeft) {
// let scrollElem = {
// target: getDomPath(item),
// scrollTop: item.scrollTop,
// scrollLeft: item.scrollLeft
// }
// scrolledElems.push(scrollElem);
// }
// });
// // удаляем все скрипты из HTML Отправляемой страницы
// correctHTML.querySelectorAll('script').forEach(function (item, i) {
// item.removeAttribute("src");
// item.innerHTML = '';
// });
// // console.log(correctHTML.innerHTML);
// // console.log(lzString.compressToUTF16(correctHTML.innerHTML));
// // определяем ширину скролла в браузере визитора
// function widthScroll() {
// var div = document.createElement('div');
// div.style.overflowY = 'scroll';
// div.style.width = '50px';
// div.style.height = '50px';
// div.style.visibility = 'hidden';
// document.querySelectorAll('#chatixContainer')[0].appendChild(div);
// var scrollWidth = div.offsetWidth - div.clientWidth;
// document.querySelectorAll('#chatixContainer')[0].removeChild(div);
// return scrollWidth;
// }
// let broadcastData = {};
// broadcastData.screenWidth = document.body.clientWidth + widthScroll();
// broadcastData.screenHeight = window.innerHeight;
// broadcastData.domain = location.origin + '/';
// broadcastData.scrolledElems = scrolledElems;
// broadcastData.visitorId = this.visitorId;
// broadcastData.htmlId = document.getElementsByTagName('html')[0].getAttribute('id');
// broadcastData.htmlClass = document.getElementsByTagName('html')[0].getAttribute('class');
// // console.log(lzString.decompressFromUTF16(lzString.compressToUTF16(correctHTML.innerHTML)));
// // console.log(correctHTML);
// this.hubConnection.invoke('PostScreenData', lzString.compressToUTF16(correctHTML.innerHTML), broadcastData)
// .then(function (result) {
// // console.log('Базовая информация отправлена');
// })
// .catch(function (err) {
// console.log(err);
// });
this.onScreenDataRequested();
});
/**
* @todo убрать логику отрисовки из Conection
*/
// let areaRemoveTimeout;
this.hubConnection.on("OnPostScreenEventByManager", (data) => {
// clearTimeout(areaRemoveTimeout);
// if (data === 'removeSelectedArea') {
// let selectedBlock = document.querySelectorAll('#managerSelected')[0];
// if (selectedBlock) {
// selectedBlock.style.display = 'none';
// }
// }
// else if (data === 'endSelectedArea') {
// areaRemoveTimeout = setTimeout(function () {
// let selectedBlock = document.querySelectorAll('#managerSelected')[0];
// if (selectedBlock) {
// selectedBlock.style.display = 'none';
// }
// }, 3500);
// }
// // рисование области выделяемой менеджером
// else {
// let selectedBlock = document.querySelectorAll('#managerSelected')[0];
// if (selectedBlock) {
// selectedBlock.style.display = 'block';
// selectedBlock.style.position = 'absolute';
// selectedBlock.style.boxShadow = '0px 0px 0px 100000px rgba(0, 0, 0, 0.6)';
// selectedBlock.style.zIndex = 1060;
// // условия для чтого что бы выделение работало не только по направления слева-направо, сверху-вниз, а в любую сторону
// selectedBlock.style.width = Math.abs(data.end.x - data.start.x) + 'px';
// selectedBlock.style.height = Math.abs(data.end.y - data.start.y) + 'px';
// if (data.start.y <= data.end.y) {
// selectedBlock.style.top = data.start.y + -document.documentElement.getBoundingClientRect().top + 'px';
// }
// else {
// selectedBlock.style.top = data.end.y + -document.documentElement.getBoundingClientRect().top + 'px';
// }
// if (data.start.x <= data.end.x) {
// selectedBlock.style.left = data.start.x + -document.documentElement.getBoundingClientRect().left + 'px';
// }
// else {
// selectedBlock.style.left = data.end.x + -document.documentElement.getBoundingClientRect().left + 'px';
// }
// }
//
this.onManagerSentScreenEvent(data);
});
this.hubConnection.on('ApplyChatroomMessage', (message, chatroomId) => {
let m = Message.buildFromInfo(message);
this.onApplyChatroomMessage(m, chatroomId);
});
this.hubConnection.on("OnConnectManagerToChatroom", (manager, chatroomId) => {
let m = Manager.buildFromInfo(manager);
this.onConnectManagerToChatroom(m, chatroomId);
});
this.hubConnection.on("OnConnectVisitorToChatroom", (member, chatroomId) => {
let v = ChatroomMember.buildFromInfo(member);
this.onConnectVisitorToChatroom(v, chatroomId);
});
this.hubConnection.on("OnDisconnectManagerFromChatroom", (manager, chatroomId) => {
let m = Manager.buildFromInfo(manager);
this.onDisonnectManagerFromChatroom(m, chatroomId);
});
this.hubConnection.on("OnDisconnectVisitorFromChatroom", (member, chatroomId) => {
let v = ChatroomMember.buildFromInfo(member);
this.onDisonnectVisitorFromChatroom(v, chatroomId);
});
this.hubConnection.on("OnCreateChatroom", (chatroom) => {
let c = Chatroom.buildFromInfo(chatroom);
this.onCreateChatroom(c);
});
this.hubConnection.on("OnUpdateChatroom", (chatroom) => {
let c = Chatroom.buildFromInfo(chatroom);
this.onUpdateChatroom(c);
});
this.hubConnection.on("OnDeleteChatroom", (chatroomId) => {
this.onDeleteChatroom(chatroomId);
});
this.hubConnection.on("OnRestoreChatroom", (chatroom) => {
let c = Chatroom.buildFromInfo(chatroom);
this.onRestoreChatroom(c);
});
this.hubConnection.on("OnUpdateConversationMessage", (message) => {
let m = Message.buildFromInfo(message);
this.onUpdateConversationMessage(m);
});
this.hubConnection.on("OnDeleteConversationMessage", (messageId) => {
this.onDeleteConversationMessage(messageId);
});
async function start() {
try {
this.hubConnection.start();
} catch (err) {
console.log(err);
setTimeout(() => start(), 5000);
}
}
this.hubConnection.onclose(async () => {
await start();
});
return await start();
/**
* @todo убрать из коннекшена
.then(function () {
this.hubConnection.invoke('GetVisitorInfo', null).then(
function (visitor) {
let url = window.location.href;
let title = null;
let titleTag = document.getElementsByTagName("title")[0];
if (titleTag) {
title = titleTag.innerHTML;
}
thiss.hubConnection.invoke('SavePageInfo', url, title);
thiss.chat.visitor = visitor;
thiss.chat.callbackSignalrConnected(visitor);
}
)
});
*/
}
/**
* Gets new visitor ID if passed was invalid.
* @param {string} websiteId Website ID from Chatix dashboard
* @returns {Promise<string>}
*/
async getNewVisitorId(websiteId) {
try {
let response = await axios.get(API_URL + '/visitor/get-id?websiteId=' + websiteId);
if (response.status !== 200) {
throw new Error("Error occured while trying to get new visitor ID. Status response status code: " + response.status);
}
return response.data;
} catch (e) {
console.error(e);
throw e;
}
}
/**
* Interrupts connection
*
*/
async stop() {
if (!this.hubConnection) {
throw new Error("Connection has to be established");
}
return await this.hubConnection.stop();
}
/**
* Sends current user input to managers
*
* @param {string} text what user is typing
* @returns {void}
*/
async sendVisitorTypedText(text) {
return await this.hubConnection.invoke('VisitorType', text);
}
/**
* Sends visitor details update to manager
*
* @param {Visitor} visitor
* @returns {Visitor} updated visitor entity
*/
async sendVisitorInfo(visitor) {
let apiVisitor = await this.hubConnection.invoke('SaveVisitorInfo', visitor);
return Visitor.buildFromInfo(apiVisitor);
}
/**
* Send user choise for screencast request.
*
* @param {bool} flag User choise to allow screencast. TRUE - allow, FALSE - disallow.
*/
async allowScreenCast(flag) {
return await this.hubConnection.invoke('AllowScreenCast', flag);
}
/**
* Sends screencast interruption event to managers
*
* @returns {void}
*/
async interruptScreenCast() {
return await this.hubConnection.invoke('InterruptScreenCast');
}
/**
* Gets all website managers
*
* @returns {Manager[]}
*/
async getWebChatManagers() {
let apiManagers = await this.hubConnection.invoke('GetWebChatManagers');
let managers = [];
for (let m of apiManagers) {
managers.push(Manager.buildFromInfo(m));
}
return managers;
}
/**
* Gets all *connected to visitor* website managers
*
* @returns {Manager[]}
*/
async getConnectedToConversationManagers() {
let apiManagers = await this.hubConnection.invoke('GetManagers');
let managers = [];
for (let m of apiManagers) {
managers.push(Manager.buildFromInfo(m));
}
return managers;
}
/**
* Gets webchat config
*
* @returns {object}
*/
async getWebChatInfo() {
return await this.hubConnection.invoke('GetWebChatInfo');
}
/**
* Gets current visitor information from server
*
* @returns {Visitor}
*/
async getVisitorInfo() {
let apiVisitor = await this.hubConnection.invoke('GetVisitorInfo', null);
return Visitor.buildFromInfo(apiVisitor);
}
/**
* Gets manager infromation by his id
*
* @param {string} managerId Manager's id
* @returns {Promise<Manager>}
*/
async getManagerInfo(managerId) {
let apiManager = await this.hubConnection.invoke('GetManagerInfo', managerId);
return Manager.buildFromInfo(apiManager);
}
/**
* Gets messages from dialog between visitor and managers.
*
* @param {string|null} lastKnownMessageId last displayed message ID. If NULL, it will return
* last messages in dialog
* @param {number} count Number of messages to return. Can be between 1 and 100.
* @returns {Promise<Message[]>}
* @throws {Error}
*/
async getConversationHistory(lastKnownMessageId = null, count = 30) {
if (count < 1 || count > 100) {
throw new Error("Count param is invalid. Valid values are between 1 and 100");
}
let apiMessages = await this.hubConnection.invoke('GetHistory', null, lastKnownMessageId, count);
let messages = [];
for (let m of apiMessages.items) {
messages.push(Message.buildFromInfo(m));
}
return messages;
}
/**
* Gets messages from specific Chatroom.
*
* @param {string} chatroomId Chatroom ID
* @param {string|null} lastKnownMessageId last displayed message ID. If NULL, it will return
* last messages in dialog
* @param {number} count Number of messages to return. Can be between 1 and 100.
* @returns {Message[]}
*/
async getChatroomHistory(chatroomId, lastKnownMessageId = null, count = 30) {
if (count < 1 || count > 100) {
throw new Error("Count param is invalid. Valid values are between 1 and 100");
}
let apiMessages = await this.hubConnection.invoke('GetChatroomHistory', chatroomId, lastKnownMessageId, count);
let messages = [];
for (let m of apiMessages) {
messages.push(Message.buildFromInfo(m));
}
return messages;
}
/**
* Returns current connection state as **INT**
* @todo перепроверить. отдает 2, хотя уже подключен.
* @return {number}
*/
getConnectionState() {
switch (this.hubConnection.connectionState) {
case 2:
return Connection.STATE_CONNECTING;
case 1:
return Connection.STATE_CONNECTED;
default:
return Connection.STATE_DISCONNECTED;
}
}
/**
* Returns current connection state as **STRING**
*
* @return {string}
*/
getConnectionStateDescription() {
switch (this.hubConnection.connection.connectionState) {
case 1:
return "Connecting";
case 2:
return "Connected";
default:
return "Disconnected";
}
}
/**
* Sends message to conversation
*
* @param {Message} message
* @return {Message} saved message instance
*/
async sendMessage(message) {
let apiMessage = await this.hubConnection.invoke('SaveMessage', message, null);
return Message.buildFromInfo(apiMessage);
}
/**
* Sends user navigation thought pages
*
* @param {string} url current page URL
* @param {string} title current page title
* @return {void}
*/
async sendPage(url, title) {
await this.hubConnection.invoke('SavePageInfo', url, title);
}
/**
* Sends data to screencast
*
* @returns {void}
*/
async sendBroadcastData(innerHTML, broadcastData) {
return await this.hubConnection.invoke('PostScreenData', lzString.compressToUTF16(innerHTML), broadcastData);
}
/**
* Sends screencast event to consultants
*
* @param {object} broadcastEvent
*/
async sendBroadcastEvent(broadcastEvent) {
let broadcastEventData = broadcastEvent;
if (broadcastEventData.mutations) {
if (broadcastEventData.mutations.length > 0) {
broadcastEventData.mutations.forEach(function (item) {
if (item.target) {
item.target = lzString.compressToUTF16(item.target);
}
});
}
}
return await this.hubConnection.invoke('PostScreenEvent', broadcastEventData, null, null);
}
/**
* Sends text message to specific Chatroom
*
* @param {Message} text Text to be sent to Chatroom
* @param {string} chatroomId Chatroom ID where message has to be sent
* @returns {Message} saved message
*/
async sendChatroomMessage(message, chatroomId) {
return await this.hubConnection.invoke('SaveChatroomMessage', message, chatroomId);
}
/**
* Gets Chatroom from backend
*
* @param {string} chatroomId Chatroom ID
*/
async getChatroom(chatroomId) {
return Chatroom.buildFromInfo(await this.hubConnection.invoke('GetChatroom', chatroomId));
}
/**
* Connects visitor to Chatroom
*
* @param {string} chatroomId Chatroom ID
*/
async connectToChatroom(chatroomId) {
let result = await this.hubConnection.invoke('ConnectToChatroom', chatroomId);
if (result.is_success) {
return true;
} else {
throw new Error(result.description);
}
}
/**
* Disconnects visitor from Chatroom
*
* @param {string} chatroomId Chatroom ID
*/
async disconnectFromChatroom(chatroomId) {
let result = await this.hubConnection.invoke('DisconnectFromChatroom', chatroomId);
if (result.is_success) {
return true;
} else {
throw new Error(result.description);
}
}
/**
* Gets all avaliable chatrooms ordered by title.
*
* @param {number} page Number of page to deliver
* @param {number} itemsPerPage Number of items per page
*/
async getAllChatrooms(page = 1, itemsPerPage = 100) {
return await this.hubConnection.invoke('GetAllChatrooms', itemsPerPage, page, false);
}
/**
* Gets all chatrooms with current visitor ordered by title.
*
* @param {number} page Number of page to deliver
* @param {number} itemsPerPage Number of items per page
*/
async getMyChatrooms(page = 1, itemsPerPage = 100) {
return await this.hubConnection.invoke('GetMyChatrooms', itemsPerPage, page, false);
}
/**
* Gets information about another visitor. It returns object similar to Visitor, but without private
* fields like email, fields, location, etc. If you need to receive this information, use REST API.
*
* @param {string} visitorId Another visitor ID
*/
async getVisitorByVisitor(visitorId) {
return ChatroomMember.buildFromInfo(await this.hubConnection.invoke('GetVisitorByVisitor', visitorId));
}
/**
* Gets visitors from specific Chatroom. If current visitor is connected to chatroom, response may
* contain himself.
*
* @param {string} chatroomId Which chatroom visitors return
* @param {number} itemsPerPage Number of visitors to return per page
* @param {number} page Data page number
*/
async getChatroomMembers(chatroomId, itemsPerPage = 10, page = 1) {
let apiMembers = await this.hubConnection.invoke('GetChatroomVisitors', chatroomId, itemsPerPage, page);
let result = [];
for (const member of apiMembers) {
result.push(ChatroomMember.buildFromInfo(member));
}
return result;
}
}
/**
* @todo убрать обработку дерева из Connection
*/
// function getDomPath(el) {
// var stack = [];
// while (el.parentNode != null) {
// var sibCount = 0;
// var sibIndex = 0;
// for (var i = 0; i < el.parentNode.childNodes.length; i++) {
// var sib = el.parentNode.childNodes[i];
// if (sib.nodeName == el.nodeName) {
// if (sib === el) {
// sibIndex = sibCount;
// }
// sibCount++;
// }
// }
// if (el.hasAttribute) {
// if (el.hasAttribute('id') && el.id != '') {
// stack.unshift(el.nodeName.toLowerCase() + "[@id='" + el.id + "']");
// } else if (sibCount > 1) {
// // потому что eq начинается с 0, а индекс xPath с 1
// sibIndex = sibIndex + 1;
// stack.unshift(el.nodeName.toLowerCase() + '[' + sibIndex + ']');
// } else {
// stack.unshift(el.nodeName.toLowerCase());
// }
// }
// el = el.parentNode;
// }
// let path = stack.slice(1);
// path = '/html/' + path.join('/')
// return path;
// }
Connection.STATE_CONNECTING = 1;
Connection.STATE_CONNECTED = 2;
Connection.STATE_DISCONNECTED = 3;
export default Connection;