ChatHW.md 7.8 KB

Chat Homework

Этапы.

Используя функцию jsonPost на адрес http://students.a-level.com.ua:10012 напишите чат-клиент, который:

Stage 0

Для поиграться скопируйте в консоль функцию jsonPost (или запустите её с этой страницы) и вызовите её с теми или иными объектами в качестве второго параметра. см. RPC.

jsonPost("http://students.a-level.com.ua:10012", {func: 'addMessage', nick: "Anon", message: 'Я не умею копипастить в консоль, зато умею жать красную кнопку.'})

Если после объявления функции jsonPost запустить пример выше, то вы напишите в чат.

Stage 1

Отправляет сообщения в чат. Для проверки отслеживайте приходящий с сервера nextMessageId, который должен увеличиваться. Интерфейс: поле ввода ника, поле ввода сообщения, кнопка отправки.

Stage 2

Читает только новые сообщения из чата. Для этого надо после каждого получения запоминать nextMessageId и отправлять его при следующем запросе новых сообщений. Изначально nextMessageId равен нулю, что бы вычитать всю историю сообщений с сервера. Интерфейс: некий div-контейнер, в котором на каждое сообщение создается div (или иной блочный контейнерный тэг) и в него помещается ник и сообщение. Также там есть timestamp который может показывать время отправки сообщения.

Stage 3

Делаем Stage 2 в setInterval для периодической проверки сообщений (раз в 2 -5 секунд).

Stage 4

Напишите асинхронную функцию отправки, которая внутри себя будет делать два запроса: на отправку и на проверку, для того что бы минимизировать задержку между отправкой сообщения пользователя и его появлением в окне чата. Оформите отдельно функции отправки и проверки новых сообщений как асинхронные (async, возвращает Promise)

Информация

jsonPost

Данная промисифицированная функция (кстати, сделайте из неё асинхронную) умеет общаться с моим чат-сервером отправляя RPC запросы используя JSON. Remote Procedure Call - вызов функций удаленно, имя функции и параметры передаются AJAX-ом в формате (например) JSON.

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.

{func: "addMessage", nick: 'msg', message: 'msg'}

Поле func является обязательным и содержит имя функции, которая должна быть вызвана на сервере. Функция на сервере получает параметром остальной объект (поля nick и message) В ответ вы получите так же объект:

{nextMessageId: 100500} 

где 100500: новая длина массива сообщений на сервере после добавления вашего сообщения.

getMessages

Позволяет прочесть часть массива сообщений от отпределенного индекса и до конца. Используется для последовательной дочитки новых сообщений. Для этого надо передать в jsonPost подобный объект:

{func: "getMessages", messageId: 0}

При значении 0 в messageId сервер отдаст сообщения от 0 до конца, т. е. весь массив:

{
	"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.

Где это делать?

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

Удачи :-)