|
@@ -0,0 +1,129 @@
|
|
|
+# Chat Homework
|
|
|
+
|
|
|
+## Этапы.
|
|
|
+Используя функцию `jsonPost` на адрес http://students.a-level.com.ua:10012 напишите чат-клиент, который:
|
|
|
+### Stage 1
|
|
|
+Отправляет сообщения в чат. Для проверки отслеживайте приходящий с сервера `nextMessageId`, который должен увеличиваться.
|
|
|
+**Интерфейс:** поле ввода ника, поле ввода сообщения, кнопка отправки.
|
|
|
+
|
|
|
+### Stage 2
|
|
|
+
|
|
|
+Читает только *новые* сообщения из чата. Для этого надо после каждого получения запоминать `nextMessageId` и отправлять его
|
|
|
+при следующем запросе новых сообщений. Изначально `nextMessageId` равен нулю, что бы вычитать всю историю сообщений с сервера.
|
|
|
+**Интерфейс:** некий `div`-контейнер, в котором на каждое сообщение создается `div` (или иной блочный контейнерный тэг) и в
|
|
|
+него помещается ник и сообщение. Также там есть `timestamp` который может показывать время отправки сообщения.
|
|
|
+
|
|
|
+### Stage 3
|
|
|
+
|
|
|
+Делаем **Stage 2** в `setInterval` для периодической проверки сообщений (раз в 2 -5 секунд).
|
|
|
+
|
|
|
+### Stage 4
|
|
|
+Напишите асинхронную функцию отправки, которая внутри себя будет делать два запроса: на отправку и на проверку, для того что бы
|
|
|
+минимизировать задержку между отправкой сообщения пользователя и его появлении в окне чата. Оформите отдельно функции отправки и
|
|
|
+проверки новых сообщений как асинхронные (`async`, возвращает `Promise`)
|
|
|
+
|
|
|
+
|
|
|
+## Информанция
|
|
|
+
|
|
|
+### `jsonPost`
|
|
|
+
|
|
|
+Данная промисифицированная функция (кстати, сделайте из неё асинхронную) умеет общаться с моим чат-сервером отправляя **RPC**
|
|
|
+запросы используя **JSON**. Это как вызов функций, только удаленно, имя функции и параметры передаются AJAX-ом в формате **JSON**.
|
|
|
+
|
|
|
+```javascript
|
|
|
+function jsonPost(url, data)
|
|
|
+ {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ var x = new XMLHttpRequest();
|
|
|
+ x.onerror = () => reject(new Error('jsonPost failed'))
|
|
|
+ //x.setRequestHeader('Content-Type', 'application/json');
|
|
|
+ x.open("POST", url, true);
|
|
|
+ x.send(JSON.stringify(data))
|
|
|
+
|
|
|
+ x.onreadystatechange = () => {
|
|
|
+ if (x.readyState == XMLHttpRequest.DONE && x.status == 200){
|
|
|
+ resolve(JSON.parse(x.responseText))
|
|
|
+ }
|
|
|
+ else if (x.status != 200){
|
|
|
+ reject(new Error('status is not 200'))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ })
|
|
|
+ }
|
|
|
+```
|
|
|
+
|
|
|
+Первым параметром указывается **URL** (см. выше) на который отправляется **POST** с **JSON**, вторым - готовый к JSONификации объект, который
|
|
|
+вы хотите отправить на сервер.
|
|
|
+
|
|
|
+### **RPC**
|
|
|
+
|
|
|
+#### `addMessage`
|
|
|
+Если вы отправите подобный **JSON** на сервер (см `jsonPost`), то сервер запишет ваше сообщение во внутренний массив и отдаст новую длину массива. После этого
|
|
|
+другие могут прочесть это сообщение, используя метод `getMessages`.
|
|
|
+```javascript
|
|
|
+{func: "addMessage", nick: 'msg', message: 'msg'}
|
|
|
+```
|
|
|
+Поле `func` является **обязательным** и содержит имя функции, которая должна быть вызвана на сервере. Функция на сервере получает параметром остальной объект (поля `nick` и `message`)
|
|
|
+**В ответ** вы получите так же объект:
|
|
|
+```javascript
|
|
|
+{nextMessageId: 100500}
|
|
|
+```
|
|
|
+где 100500: новая длина массива сообщений на сервере после добавления вашего сообщения.
|
|
|
+
|
|
|
+#### `getMessages`
|
|
|
+
|
|
|
+Позволяет прочесть *часть* массива сообщений от отпределенного индекса и до конца. Используется для последовательной *дочитки новых* сообщений. Для этого надо передать в `jsonPost` подобный объект:
|
|
|
+```javascript
|
|
|
+{func: "getMessages", messageId: 0}
|
|
|
+```
|
|
|
+При значении 0 в `messageId` сервер отдаст сообщения от 0 до конца, т. е. весь массив:
|
|
|
+```javascript
|
|
|
+{
|
|
|
+ "data": [
|
|
|
+ {
|
|
|
+ "nick": "test",
|
|
|
+ "message": "test",
|
|
|
+ "timestamp": 1524225450317
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "nick": "test",
|
|
|
+ "message": "test2",
|
|
|
+ "timestamp": 1524225460973
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "nick": "test",
|
|
|
+ "message": "test3",
|
|
|
+ "timestamp": 1524225504849
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "nick": "SirkoSobaka",
|
|
|
+ "message": "Hello!",
|
|
|
+ "timestamp": 1524226323310
|
|
|
+ },
|
|
|
+ {
|
|
|
+ "nick": "SirkoSobaka",
|
|
|
+ "message": "Hello!",
|
|
|
+ "timestamp": 1524226326628
|
|
|
+ },
|
|
|
+ ],
|
|
|
+ "nextMessageId": 5
|
|
|
+}
|
|
|
+```
|
|
|
+После чего вы итерируете по `data` и выводите каждый отдельный объект как **DOM**-элемент с текстом, и, возможно, вложенной версткой (время в отдельном элементе и т.п.)
|
|
|
+
|
|
|
+`nextMessageId` вы запоминаете для того, что бы отправить следующий запрос начиная с него (т. е. с 5 в примере выше). Тогда сервер отдаст вам *только сообщения новее последнего
|
|
|
+запроса*.
|
|
|
+
|
|
|
+### Chat Server
|
|
|
+Можно глянуть тут: http://gitlab.a-level.com.ua/gitgod/FrontendLectures/src/master/chatServer/server.js
|
|
|
+Обратите внимание на массив `messages` и на функции в ассоциативном массиве `RPCFuncs`. А также на
|
|
|
+http://gitlab.a-level.com.ua/gitgod/FrontendLectures/src/master/chatServer/server.js#L43-L51
|
|
|
+
|
|
|
+### Спойлер
|
|
|
+
|
|
|
+http://chat.asmer.fe.a-level.com.ua/
|
|
|
+
|
|
|
+Но вам все равно надо переписать это на `async`, `await`, `Promise` и **DOM**.
|
|
|
+
|
|
|
+
|
|
|
+## Удачи :-)
|