В качестве транспорта используется Flash.Network.NetConnection и AMF3. В протоколе есть и push-, и pull-методы. В дальнейшем, push-методы помечены [MSG] и далее именуются сообщениями, pull - [RPC]. Для push-вызовов используется единая точка входа event
public function event(type : String, message : String, data : Object) : void
Этот метод должен быть определен у объекта, используемого как NetConnection.client.
Аутентификация проводится при вызове NetConnection.connect через дополнительный параметр, передаваемый клиенту через flashvars:
var token = loaderInfo.parameters.token;
var _nc = new NetConnection();
_nc.connect(server, token);
После этого клиент должен ожидать либо разрыва соединения(NetConnection.Connect.Rejected
, не авторизован), либо вызова event("init", role, self:User)
.
Роли пользователей по сути всего лишь маркеры для наборов разрешений. Итоговый набор разрешений пользователя может быть изменен на лету админом. На данный момент эти наборы разрешений выглядят так:
default_acl(<<"admin">>) ->
[can_grant,
can_prolong,
can_moderate
| default_acl(<<"active">>) ];
default_acl(<<"chosen_one">>) ->
[can_present,
can_start_vote];
default_acl(<<"active">>) ->
[can_chat,
can_ask_voice];
default_acl(<<"passive">>) ->
[can_vote].
Пояснения по коду выше:
- роль admin расширяет роль active.
- роль chosen_one не является самостоятельной, это mixin, добавляемый к active/admin.
Нижеследующее описание методов RPC сгруппировано по логическому типу сообщения. Под записью
[MSG] userJoin(User)
следует понимать следующий вызов с сервера:
event("presence", "userJoin", data : User)
Описанные следующим образом функции
[RPC] message (ChatMessage())
[RPC] load_chat : Array<Message>
следует вызывать соответственно так:
var nc: NetConnection;
....
var msg = new ChatMessage();
msg.text = "some text";
nc.call('message', null, msg);
и так:
function onChatLoad(messages : Array) : void
{
for each(var u : ChatMessage in messages) {
....
}
}
var nc: NetConnection;
....
nc.call('load_chat', new Responder(onChatLoad));
[MSG] userJoin(User)
пользователь подключился
[MSG] userLeave(User)
пользователь отключился
[MSG] askingVoice(SessID)
пользователь просит голос
[RPC] list_users : Array<User>
получить список пользователей
[RPC] get_asks : Array<int>
возвращает список просьб голоса(SessID пользователя), в правильном порядке.
[MSG] chatMessage (ChatMessage)
Пришло новое сообщение в чат
[RPC] message (ChatMessage())
Отправить сообщение
[RPC] load_chat : Array<ChatMessage>
Загрузить все сообщения чата
[MSG] moderateMessage (ChatMessage)
Новое сообщение на модерацию.
[MSG] removeMessage (ChatMessage)
Модерация сообщения выполнена другим модератором
[RPC] load_unmoderated : Array<ChatMessage>
Загрузка всего списка немодерированных сообщений.
[RPC] accept (ChatMessage)
Пропустить сообщение в общий чат.
[RPC] reject (ChatMessage)
Заблокировать сообщение.
[RPC] pass_up (ChatMessage)
Отправить сообщение ведущему/ведущим.
[MSG] startPublish (StreamData)
Начать публикацию потока на сервер. В StreamData смысл имеет только name, соединение используется уже установленное.
[MSG] stopPublish
Очевидно.
[MSG] addStream (StreamData)
Добавить поток в отображение. Если StreamData.server_url == null, использовать текущее соединение с сервером.
[MSG] updateStream (StreamData)
Обновить данные потока c id == StreamData.id.
[MSG] removeStream (ID)
Очевидно.
[RPC] get_streams : Array<StreamData>
Получить список отображаемых потоков.
Здесь я еще ничего не решил пока.
[MSG] set_url (URL)
TODO
[RPC] get_presentations : Array<String>
Список URL индекс-файлов презентаций, которые пользователь добавил к конференции в веб-интерфейсе.
Главная часть индекс-файла - массив pages, в котором находятся непосредственно URL отдельных слайдов.
[RPC] set_slide (URL)
TODO
[RPC] get_polls : Array<Poll>
получить список своих опросов
[RPC] start_poll (PollID, ?timeout)
начать опрос, опционально время опроса
[RPC] vote (PollID, indexOfAnswer)
ответ на опрос. indexOfAnswer - индекс выбранного ответа в Poll.answers.
[MSG] newPoll (Poll)
Уведомление о старте опроса.
[MSG] newVote ({PollId, indexOfAnswer})
Уведомление о голосе от пользователя (для реалтайм отображения процесса опроса).
Presentation {
id: Number;
label, slug : String;
slides : Array<String>;
}
ChatMessage {
registerClassAlias("Message", ChatMessage);
id : Number; // filled on server
author_name, author_id : String; // filled on server
timestamp : Date = new Date();
text : String;
}
User {
registerClassAlias("User", User);
// TODO: здесь должен быть какой-то вменяемый ID.
id : Number;
name : String;
role : String;
}
StreamData {
id : Number,
server_url : String; // if null use main server
stream_name : String;
audio_only : Boolean;
}
Poll {
id: Number;
question: String;
maxAnswersCount: Number; // количество возможных вариантов ответа.
// если >1 - пользователь может проголосовать за несколько пунктов.
// но это в будущем - сейчас можно только один ответ.
answers: Array<String>;
}