Pull to refresh

Клиент для «Сервер push сообщений»

Reading time6 min
Views3K
Продолжение публикации «Сервер push сообщений»

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



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

Аналогично можно изменить ширину списка контактов и списка сообщений.

Отправка сообщений анимирована, какой либо анимации при отправке сообщений в других программах не было.

Для фона списка контактов используется градиент серого и розового, похожее сочетание можно встретить на небе в виде зарева.

У пользователей онлайн — оранжевый цвет имени, подключенные комнаты(группы) черного цвета. Пользователи не онлайн и отключенные группы — серого цвета. Отличить комнату от пользователя в списке контактов можно по звездному названию, названия комнат начинаются с ✯



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



Есть возможность пересылки файлов, файлы картинок пересылаются сразу в сообщении и отображаются в сообщении. Видео файлы не пересылаются сразу, отправляется только первый кадр, для скачивания необходимо запустить видео. Остальные файлы аналогично скачиваются только после клика по файлу в сообщении. Максимальный размер файла, а также размер части файла, на которые разбиваются большие файлы, настраивается в push0k admin. Для отправки файла можно воспользоваться кнопкой «отправить вложение», также, можно просто перетащить файл в окно сообщений. Аналогично, присланный файл из сообщения можно перетащить в папку проводника или finder в Mac OS. Иными словами для файлов реализован drag & drop.



В сообщениях удаляются html теги. Но есть похожая на markdown разметка.

* жирный *
~ курсив ~
_ подчеркнутый _

Можно отправлять ссылки, но ссылка должна быть отдельным сообщением.

В каждом сообщении есть кнопки:

“” цитирование сообщения
➦ пересылка сообщения



Для безопасного соединения с сервером реализована кнопка с замком. Логика аналогична браузерам — небезопасный сертификат, просроченный, само подписанный или от другого доменного имени, замок открыт — соединение небезопасно. По кнопке с замком открывается информация сертификата.



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



В сообщениях не реализована отправка смайлов. Нет видео и аудио связи. Нет возможности демонстрации экрана пользователя. В дальнейшем что-то из перечисленного обязательно реализую.

Скачать push0k client:

windows
Mac OS

Приложение сделано на electron с использованием vue.js. Приложение бесплатно, но в отличии от сервера описанного в первой части статьи, исходный код открывать пока не планирую.

Пример подключения


Подключение состоит из трех частей:

  1. Установка соединения.

    Для защищенного соединения это обмен handshake-сообщениями.
  2. Авторизация.

    При авторизации помимо логина передается хеш от хеша пароля + id соединения.

    В сообщении авторизации передаются параметры компьютера тип ОС, версия ОС, процессор, память, имя компьютера. Эти справочные данные необходимы для статистики и понимания как влияет тип ОС, процессор и память на скорость подключения, обмена данными и.т.д.

    Первые версии программы делались и работали из 1с. Обычно, на одном компьютере может запускаться не одна база данных 1с, а несколько например ЗУП и БП у бухгалтера. Если решение используется для поддержки бухгалтерии, важно понимать, из какой базы отправлено сообщение бухгалтера. При авторизации также передаются данные базы данных.
  3. Синхронизация данных.

    После получения сообщения об успешной авторизации, на сервер отправляется сообщение запрос данных с датой. Самая большая дата последнего сообщения или последнего изменения пользователя или комнаты (группы). По переданной дате определяются новые сообщения или измененные пользователи, комнаты(группы). Дата может быть и пустой, тогда получаются все сообщения пользователи и комнаты, такое может быть при первом подключении.

    После получения данных синхронизации, на сервер отправляется сообщения подтверждения получения данных и подсчитанное время «установки соединения», «авторизации», «синхронизации данных».

Подключение socket.io к html странице.


Для node.js

  • открыть консоль
  • перейти в папку проекта команда `cd /yourCatalog`
  • выполнить команду установки `npm install socket.io`

Код примера node.js:

const io = require('socket.io-client');
const crypto = require('crypto');
const os = require('os');
const cpusarray = os.cpus();
let actiontime = 0;
let contime = 0;
let auftime = 0;
let datasintime = 0;
let socket;
let lastdatesync = new Date(0).toISOString();
let usernumber = '+7 (999) 777-77-77';
let pw = 'somePassword';
let baseref = process.cwd();
let basename = 'push0k client';
let baseid = crypto
  .createHash('md5')
  .update(appdirectory)
  .digest('hex');
baseid =
  baseid.substring(0, 8) + '-' + 
  baseid.substring(8, 12) + '-' + 
  baseid.substring(12, 16) + '-' + 
  baseid.substring(16, 20) + '-' + 
  baseid.substring(20, 32);
let basever = '19.02';
let clientid = crypto
  .createHash('md5')
  .update(os.hostname())
  .digest('hex');
clientid =
  clientid.substring(0, 8) + '-' +
  clientid.substring(8, 12) + '-' +
  clientid.substring(12, 16) + '-' +
  clientid.substring(16, 20) + '-' +
  clientid.substring(20, 32);
let syncdata = '';
let syncdatasize = 0;

function sha256(p) {
  const hash = crypto.createHash('sha256');
  hash.update(p);
  return '' + hash.digest('hex');
}

function connect() {
  socket = io('http://yourServer.com:6789', { transports: ['websocket'], timeout: 5000 });
  socket.connect();
  socket.on('connect', onconnect);
  socket.on('message', onmessage);
  actiontime = new Date().getTime();
}

function onconnect() {
  contime = new Date().getTime() - actiontime;
  usernumber = usernumber.replace(/\D/g, '');
  socket
    .binary(false)
    .emit(
      'message',
      '{"event":"auf","user":"' +
        usernumber +
        '","password":"' +
        sha256(pw + socket.id) +
        '","roomsjoin":true,"basename":"' +
        basename +
        '","basever":"' +
        basever +
        '","baseid":"' +
        baseid +
        '","baseref":"' +
        encodeURIComponent(baseref) +
        '","osversion":"' +
        encodeURIComponent(os.release()) +
        '","appversion":"18.08","clientid":"' +
        clientid +
        '","infappview":"","ram":"' +
        os.totalmem() / 1024 / 1024 +
        '","proc":"' +
        encodeURIComponent(cpusarray[0].model) +
        '","ostype":"' +
        encodeURIComponent(os.type() + ' ' + os.arch()) +
        '","compname":"' +
        encodeURIComponent(os.hostname()) +
        '"}'
	);
  // Настройки передачи файлов с сервера
  let filetranfer = msgdata.filetranfer;
  let filemaxsize = msgdata.filemaxsize;
  let filepartsize = msgdata.filepartsize;	
  actiontime = new Date().getTime();
}

function onmessage(msg) {
  let msgdata;
  let mestime = new Date().getTime();
  if (typeof msg === 'string') {
    try {
      msgdata = JSON.parse(msg);
    } catch (err) {
      this.message = err.toString();
      return;
    }
  } else if (typeof msg === 'object') {
    msgdata = msg;
  }
  if (msgdata.event === 'connected') {
    auftime = mestime - actiontime;
    socket
      .binary(false)
      .emit(
        'message',
        '{"event":"getData","userid":"' +
          msgdata.userid +
          '","id":"' +
          msgdata.id +
          '","baseid":"' +
          baseid +
          '","clientid":"' +
          clientid +
          '","lastdatesinc":"' +
          lastdatesync +
          '"}'
      );
    if (msgdata.setpass === 'true') {
      // временный пароль должен быть изменен пользователем
      // в модальном диалоге без возможности отказа
      // openDialogSetNewPassword();
    }
    actiontime = new Date().getTime();
  } else if (msgdata.event === 'datasync') {
    syncdata += msgdata.data;
    syncdatasize += Buffer.byteLength(msg, 'utf8');
    if (msgdata.dataPart < msgdata.partsCount) {
      return;
    }
    datasintime = mestime - actiontime;
    socket
      .binary(false)
      .emit(
        'message',
        '{"event":"dataConfirm","userid":"' +
          msgdata.userid +
          '","dataid":"' +
          msgdata.dataid +
          '","baseid":"' +
          baseid +
          '","contime":' +
          contime +
          ',"auftime":' +
          auftime +
          ',"datasintime":' +
          datasintime +
          ',"datesync":"' +
          msgdata.datesync +
          '","datasize":' +
          syncdatasize +
          '}'
      );
    contime = 0;
    datasintime = 0;
    auftime = 0;
    syncdatasize = 0;
    let datasync = JSON.parse(Buffer.from(syncdata, 'base64').toString('utf8'));
    syncdata = '';
    // обработка полученных данных с сервера
    // datasync.Users массив пользователей
    // datasync.Rooms массив комнат
    // datasync.Cons массив подключений пользователей
    // datasync.joinedRooms массив подключенных комнат
    // datasync.Mess массив сообщений
  }
}
Tags:
Hubs:
Total votes 11: ↑7 and ↓4+3
Comments3

Articles