Этот документ описывает протокол общения между клиентом GG-чата и сервером GG-чата. Сам документ находится в стадии черновика и любая его часть может быть изменена. После того, как протокол будет зафиксирован, ему будет присвоена соответсвующая версия. Предпологается, что протокол открытый и не привязан к конкретной клиентской технологии. Любой желающий может реализовать клиента, поддерживающего этот протокол. (Например клиент для iOS или Android.)
- Основан на JSON-кодировании.
- Максимальная длина сообщения 4кб, включая JSON-разметку.
- Под асинхронностью понимается то, что после отправки сообщения одной из сторон, не обязательно прийдет ответ именно на это сообщение.
- За 1 раз отсылается 1 сообщение.
- Обмен возможен только между клиентом и сервером, т.е. минуя сервер, клиенты общаться не могут.
- Одно соединение может обслуживать несколько каналов (стримов).
req_to_server - запрос клиента к серверу res_to_client - ответ сервера клиенту res_to_all - ответ сервера всем клиентам res_to_all_in_channel - ответ сервера всем клиентам в определенном канале channel_id - идентификатор канала
Для подключения к серверу чата следует использовать websocket-соединение по адресу:
ws://chat.goodgame.ru:8081/chat/websocket
Для web-браузеров рекомендуется использовать библиотеку sockjs-client В этом случае, url-соединения будет
http://chat.goodgame.ru:8081/chat
{
type: "", // заголовок сообщения
data: {
//Дополнительная информация.
}
}data - вынесена в отдельную json сущность, для более удобного разбора параметров сообщения.
//res_to_client
{
type: "welcome",
data: {
protocolVersion: 1.1,
serverIdent: "GG-chat/1.0 beta"
}
}Клиент опционально, сверяет версию протокола. После чего либо отключается, либо продолжает работать.
//req_to_server
{
type: "auth",
data: {
user_id: "123", // идентификатор пользователя на сайте, либо 0 для гостей
token: "123123fhjdhfjd" // ключ авторизации. Если не указан, то будет запрошен гостевой доступ.
}
}
//res_to_client
{
type: "success_auth",
data: {
user_id: "123", // id-пользователя на сайте, для гостей 0
user_name: "Василий" // nick на сайте, для гостей ""
}
}//req_to_server
{
type: "get_channels_list",
data: {
start: 0, // стартовая позиция (отсчет с 0)
count: 50 // количество каналов на страницу (max - 50)
}
}
//res_to_client
{
type: "channels_list",
data: {
channels: [{
channel_id: "5",
channel_name: "имя канала",
clients_in_channel: 545, // всего клиентов в канале, включая гостей
users_in_channel: 332, // всего авторизованных пользователей в канале
},
...] // массив каналов, где есть хотя бы 1 пользователь, гости не считаются.
}
}Список каналов сортируется по количеству пользователей. На первой позиции чат с наибольшим показателем.
Если channel_id известен заранее, то это сообщение можно не отсылать.
//req_to_server
{
type: "join",
data: {
channel_id: "5" // идентификатор канала
hidden: false // для модераторов: не показывать ник в списке юзеров
}
}Если сервер присоединяет клиента к каналу, то клиент информируется сообщением.
//res_to_client
{
type: "success_join",
data: {
channel_id: "5",
channel_name: "имя канала",
motd: "Сообщение дня", // сообщение дня
slowmod: 0, // задержка в секундах между отправкой сообщений
smiles: 1,
smilePeka: 1,
clients_in_channel: 545, // всего клиентов в канале, включая гостей
users_in_channel: 332, // всего авторизованных пользователей в канале
user_id: "123", // для гостей "0"
name: "Василий", // для гостей ""
access_rights: "1", // по этому полю клиент понимает права пользователя, в этом канале.
premium: true,
is_banned: false, // забанен или нет в этом канале
banned_time: 0, // до какого времени забанен.
reason: 'Провоцирование', // текстовая строка с причиной бана.
payments: "128.30",
paidsmiles: ["1","2","3"]
}
}В данной реализации протокола, гости находятся в состоянии readonly.
//req_to_server
{
type: "unjoin",
data: {
channel_id: "5" // идентификатор канала
}
}
//res_to_client
{
type: "success_unjoin",
data: {
channel_id: "5"
}
}//res_to_client
{
type: 'join_to_room',
data: {
channel_id: "123", // id-канала, из которого посылалась inline-команда /join
room_id: "5" || "r5" // id-канала или если начинается с префикса "r" id-комнаты
}
}//req_to_server
{
type: "get_users_list",
data: {
channel_id: "5"
}
}Список пользователей в канале. Гости не учитываются.
//res_to_client
{
type: "users_list",
data: {
channel_id: "5",
clients_in_channel: 545, // всего клиентов в канале, включая гостей
users_in_channel: 332, // всего авторизованных пользователей в канале
users: [{
id: '55828',
name: 'dfcz',
rights: 20,
premium: false,
payments: 'null',
mobile: false,
hidden: false
},
...] // Массив пользователей которые в данный момент находятся в канале
// для экономии памяти, клиент может игнорировать этот список.
}
}//req_to_server
{
type: "get_channel_counters",
data: {
channel_id: "5"
}
}Счетчик клиентов и пользователей, подключенных к каналу.
//res_to_client
{
type: "channel_counters",
data: {
channel_id: "5",
clients_in_channel: 545, // всего клиентов в канале, включая гостей
users_in_channel: 332, // всего авторизованных пользователей в канале
}
}inline-команда /list
//res_to_client
{
type: "list",
data: {
channel_id: "5",
users: [{
id: "6",
name: "Василий"
},
...
]
}
}//req_to_server
{
type: "get_ignore_list",
data: {
}
}Список общий для всех каналов.
//res_to_client
{
type: "ignore_list",
data: {
users: [{
id: "6",
name: "Василий"
},
...
]
}
}//req_to_server
{
type: "add_to_ignore_list",
data: {
user_id: "77"
}
}Ответ аналогичен команде get_ignore_list
//req_to_server
{
type: "del_from_ignore_list",
data: {
user_id: "77"
}
}Ответ аналогичен команде get_ignore_list
//req_to_server
{
type: "get_channel_history",
data: {
channel_id: "5"
}
}
//res_to_client
{
type: "channel_history",
data: {
channel_id: "5",
messages:[{
user_id: "123", // id юзера.
user_name: "Василий",
user_group: 1, // на основе группы, определяется каким цветом выводить сообщения
message_id: "100", // номер сообщения, нужно для удаления сообщения из чата.
timestamp: unixtime, // время прихода сообщения на сервер.
text: "Всем чмоки в этом чатике." // оригинальное сообщение, за исключением того, что html-разметка эскейпится.
// клиент сам занимается преобразованием спец. символов (например подстановка смайлов).
},
...] // Массив сообщений, более раннии сообщения первее.
}
}//res_to_client
{
type: "motd",
data: {
channel_id: "5",
moder_id: 123,
moder_name: 'Валера',
moder_group: 1,
text: "Сообщение дня"
}
}//res_to_client
{
type: "slowmod",
data: {
channel_id: "5",
moder_id: 123,
moder_name: 'Валера',
moder_group: 1,
slowmod: 0 // в секундах
}
}//req_to_server
{
type: "send_message",
data: {
channel_id: "5",
text: "Всем чмоки в этом чатике.", //html-разметка эскейпится
hideIcon: false, // используется в служебных целях на стороне клиента
mobile: false // используется в служебных целях на стороне клиента
}
}Если сообщение начинается с "/", то оно считается командой и соответствующим образом обрабатывается на сервере.
Список доступных команд:
- /list - аналогично сообщению "get_users_list"
- /nick - аналогично сообщению "success_join", только поле type будет "user_info"
- /me - сервер отошлет всем клиентам в канале специально сформированное сообщение
- /slap - сервер отошлет всем клиентам в канале специально сформированное сообщение
- /motd - устанавливает сообщение дня
- /smiles 1 | 0 - включение, отключение смайлов
//res_to_all_in_channel
{
type: "message",
data: {
channel_id: "5",
user_id: "123", // id юзера.
user_name: "Василий",
user_rights: 10, // на основе прав, определяется каким цветом выводить сообщения
premium: false, // премиум статус пользователя отправившего сообщение
hideIcon: false, // используется в служебных целях на стороне клиента
mobile: false, // используется в служебных целях на стороне клиента
payments: "123.45",
paidsmiles: [],
message_id: "100", // номер сообщения, нужно для удаления сообщения из чата.
timestamp: unixtime, // время прихода сообщения на сервер.
color:"#6633FF", // цвет сообщения
text: "Всем чмоки в этом чатике." // оригинальное сообщение, за исключением того, что html-разметка эскейпится.
// клиент сам занимается преобразованием спец. символов (например подстановка смайлов).
}
}//req_to_server
{
type: "send_private_message",
data: {
channel_id: "5",
user_id: "124" //получатель
text: "Привет, как дела?" // обрабатывается аналогично всем сообщениям
}
}//res_to_client
{
type: "private_message",
data: {
channel_id: "5",
user_id: "124", // отправитель
user_name: "Василий",
target_id: 124, // получатель
target_name: "Валера",
timestamp: unixtime,
text: "Привет, как дела?" // обрабатывается аналогично всем сообщениям
}
}//req_to_server
{
type: "remove_message",
data: {
channel_id: "5",
message_id: "100" //номер сообщения которое нужно удалить.
}
}При этом сервер отсылает также всем клиентам в канале сообщение
//res_to_all_in_channel
{
type: "remove_message",
data: {
channel_id: "5",
message_id: "100" //номер сообщения которое нужно удалить.
}
}//req_to_server
{
type: "ban",
data: {
channel_id: "5", // канал в котором вынесен бан
ban_channel: "5", // канал в котором необходимо забанить, если 0 - то на все каналы
user_id: "124",
duration: 3600, // время бана в секундах
reason: "Плохо себя вёл", //причина
comment: "Я вас всех шатал", // текст сообщения, за который вынесен бан
show_ban: true // показывать ли бан
}
}Что бы всем в чате было видно, кого и за что.
//res_to_all_in_channel
{
type: "user_ban",
data: {
channel_id: "5",
user_id: "124", // id забаненого пользователя
user_name: "Василий", // ник забаненого пользователя
moder_id: "123", // id пользователя, вынесшего бан
moder_name: "Валера", // ник пользователя, вынесшего бан
moder_group: 1, // на основе группы, определяется каким цветом выводить сообщения
duration: 3600, время на сколько забанен пользователь в секундах
reason: "Плохо себя вёл"
}
}//req_to_server
{
type: "warn",
data: {
channel_id: "5",
user_id: "124", // кого предупреждаем
reason: "Плохо себя ведешь" //причина
}
}Что бы всем в чате было видно, кого и за что.
//res_to_all_in_channel
{
type: "user_warn",
data: {
channel_id: "5",
user_id: "124", // id пользователя, кому вынесено предупреждение
user_name: "Василий", // ник забаненого пользователя
moder_id: "123", // id пользователя, вынесшего предупреждение
moder_name: "Валера", // ник пользователя, вынесшего бан
moder_group: 1, // на основе группы, определяется каким цветом выводить сообщения
reason: "Плохо себя ведешь"
}
}//req_to_server
{
type: "new_poll",
data: {
channel_id: "5",
title: "Зеленое или старкрафт?", // заголовок голосования
answers: [{text: "Зеленое"} {text: "старкрафт"}, {text: "я упырь"}], // массив вариантов, не больше 6
}
}После создания голосования, клиенты получают сообщение
//res_to_all_in_channel
{
type: "new_poll",
data: {
channel_id: "5",
moder_id: 6,
moder_name: "Василий",
title: "Зеленое или старкрафт?", // заголовок голосования
answers: [{id: 1, text: "Зеленое"}, {id: 2, text: "красное"}, {id: 3, text: "я упырь"}], // массив вариантов, не больше 6
}
}//req_to_server
{
type: "get_poll",
data: {
channel_id: "5"
}
}Ответом будет сообщение new_poll, если этот пользователь еще не голосовал или poll_results - если голосовал
//req_to_server
{
type: "vote",
data: {
channel_id: "5",
answer_id: 1
}
}//req_to_server
{
type: "get_poll_results",
data: {
channel_id: "5",
}
}//res_to_client
{
type: "poll_results",
data: {
channel_id: "5",
voters: 200, // количество проголосовавших
title: "Зеленое или старкрафт?", // заголовок голосования
answers: [{id: 1, text: "Зеленое", voters: 100}, {id: 2, text: "красное", voters: 50}, {id: 3, text: "я упырь", voters: 50}] // массив вариантов, не больше 6
}
}Клиент сам строит график и высчитывает процентное соотношение. Так же сам решает, что делать, если во время отображения результатов голосования, приходит сообщение "new_poll" (Новое голосование).
//req_to_server
{
type: "get_user_info",
data: {
user_id: "124"
}
}//res_to_client
{
type: 'user',
data: {
user_id: "124",
name: "Abcd"
}
}Пользователь, обладающий правами выше или равных правам стримера, может назначать/снимать помошников стримера для выбранного канала
Уровни прав описаны ниже.
//req_to_server
{
type: "make_moderator",
data: {
channel_id: "5",
user_id: "124"
}
}//req_to_server
{
type: "clean_moderator",
data: {
channel_id: "5",
user_id: "124"
}
}Если изменяются права текущего пользователя в чате то клиент получает следующее сообщение.
//res_to_client
{
type: 'update_rights',
data: {
channel_id: "5",
access_rights: 10
}
}Клиент может запросить статус премиума текущего пользователя для выбранного канала.
//req_to_server
{
type: "refresh_premium",
data: {
channel_id: 5
}
}Если текущий пользователь имеет премиум для этого канала, то сервер вернет следующее сообщение
//res_to_client
{
type: 'update_premium',
data: {
channel_id: 5,
premium: true
}
}//res_to_client
{
type: "error",
data: {
channel_id: "5",
error_num : 201, // Идентификатор ошибки, разбиты по уровням.
errorMsg: 'Не достаточно прав' // Готовое сообщение.
}
}Уровни ошибок:
- 0..100 технические ошибки, например неверный синтаксис сообщений, или проблемы на сервере с обработкой запроса.
- 101..200 ошибки связанные с данными, например неверный идентификатор канала, несуществующий id пользователя
- 201..300 ошибки связанные с правами пользователя, например не достаточно прав на удаление сообщения.
Клиент по номеру ошибки, должен соответствующим образом проинформировать пользователя.
| Код | Название | Уровень |
|---|---|---|
| casual | Обычный | 0 |
| stream_moder | Помошник стримера | 10 |
| streamer | Стример | 20 |
| moderator | Модератор | 30 |
| smoderator | Супермодератор | 40 |
| admin | Администратор | 50 |
Для разных каналов доступен разный набор смайлов. Весь набор смайлов, а также их тип можно получить по url:
http://goodgame.ru/js/minified/global.js
Рассмотрим структуру ответа:
var Global = {
Smiles : [{"bind":"11","name":"thup","donat":0,"premium":1,"paid":0}, ... ],
Channel_Smiles : {"1577":[{"bind":"1","name":"shimoro2","donat":0,"premium":1,"paid":0}, ... }
...
}
Ключ Smiles отвечает за общедоступные смайлы, Channel_Smiles - за смайлы, привязанные к конкретному каналу.
Так же, каждый смайл описан следующим набором характеристик:
bind- для внутренних нужд,name- код смайла в тексте сообщения,donat- признак донатного смайла (уровни доната расписаны ниже),premium- премиум смайл (является ли пользователь премиум-клиентом в данном канале можно узнать из собщенийsuccess_join,message,private_messageили отправивrefresh_premium)paid- признак платного смайла (узнать список доступных платных смайлов можно в полеpaidsmilesиз собщенийsuccess_join,message,private_message)
Уровни доната для смайлов зависят от доната пользователя, которое можно узнать из собщений success_join, message, private_message поле payments:
- donat0 < 100
- 1 >= 100, < 300
- 2 >= 300, < 500
- 3 >= 500, < 3000
- 4 >= 3000, < 10000
- 5 >= 10000
Так же, все платные смайлы доступны клиентам с правами больше чем стримерские (стримеру, модераторам, супермодераторам и админам).
Если текущий пользователь является стримером, то сервер дополнительно уведомляет о донате и активации премиумов:
Донат:
// res_to_client
// Поля total и title передаются только при донате в призовой фонд турнира
{
type: "payment",
data: {
channel_id: "5",
userName: "Петя",
amount: 199,
message: "Эгегей!",
total: 230,
title: "Турнир номер 1"
}
}Активация премиума:
//res_to_client
{
type: "premium",
data: {
channel_id: "5",
userName: "Петя"
}
}