В скриптах для запуска нужно удалить код, проверяющий версию ОС. Ну или можно не удалять, он безобидный, только варнинги выдает.
WARNING: Your Linux distribution, RedHat i686 is not supported by this
installer.
Ага, напугал. Все равно будешь у меня работать )
Дальше начинается просто вакханалия крючкотворства. Дело в том, что Adobe выблевнула в 2009 году «спецификацию» RTMP. Этот документ описывает некоторый протокол, который очень похож на RTMP и Adobe упорно называет то, что описывает этот документ, как RTMP. И более того: в документе сказано, что после прочтения этого документа, вы не имеете права реализовывать RTMP серверы иначе, кроме как по этому документу. Отступление на один байт от этого документа лишает вас права использовать этот документ.
levgem.livejournal.com
Итак, у меня класс FmsService, отвечающий за отправку данных на сервер наследуется от прокси. Это значит, что я могу не дублировать каждый серверный метод в этом классе, чтобы его вызывать.
Сейчас в быстром прототипе этот же класс и принимал вызовы с сервера. И вот сервер пытается вызывать метод, который я забыл определить в FmsSevice. И чего происходит? FmsService вызывает такой метод с таким же именем на сервере! Который, к несчастью, там оказался в наличии.
Выводы:
1) Прокси — опасная штука, способная ловко прятать причину бага
2) Не стоит идентично называть методы на клиенте и на сервере
Вот очередная статья на сайте (глава в книге) yzh44yzh.com
Предлагаю высказаться по наброску оглавнения книги github.com (хотя может еще рано).
И анонсирую новый проект github.com Ну как новый, для меня-то старый. Просто раньше не выкладывал.
one application.onConnect() handler is executed at a time. It’s a good idea to write code for the
application.onConnect() function that is executed quickly to prevent a long connection time for clients.
Бля, я идиот, и почему я раньше этого не замечал в документации? У меня onConnect — весьма тяжелый метод. Надо переделать.
Это известная проблема FMS.
И из-за этого во всех наших FMS приложениях существуюет костыль, входящий с состав нашей core-fms-библиотеки — клиент каждые N секудн посылает запрос keepAlive, а сервер запоминает timestump, когда был получен последний такой запрос от данного клиента. Затем сервер каждые M секунд (M примерно равно N * 2) перебирает массив application.clients и проверяет timestump каждого клиента. Те, кто давно не посылал keepAlive — зомби, и их нужно убирать.
Увы, с этим костылем переодически возникает другая проблема — FMS ошибочно дисконнектит живых клиентов. По каким-то неизвестным причинам изредко бывает так, что timestump клиента устарел, хотя клиент жив и спокойно работает.
Сча придумал еще один костыль поверх — клиентов с устаревшим timestump не удалять сразу, а посылать им запрос areYouAlive(someUniqueKey), на который клиент должен ответить someUniqueKey. Живой клиент ответит, зомби нет.
Запрос, ясное дело, асинхронный. Так что еще нужно будет и здесь реализовать timeout на ожидание ответа клиента.
В общем, хак на хаке. Так и живем :)
yzh44yzh.com тул для профилирования по производительности.
Хотя я и так знаю, что никому не нужно. Но все равно буду выкладывать, не отвертитесь :)
А кому-нибудь нужны всякие либы для разработки под FMS? Например, поддержка юнит-тестов, или вот Хотя я и так знаю, что никому не нужно. Но все равно буду выкладывать, не отвертитесь :)
Для начала нужно напустить на него кучу клиентов-ботов :)
— запуск сервера самый быстрый у wowza, медленне у red5, самый медленный у fms (правда это включая запуск админ-сервера)
— коннект приложения к wowza и red5 примерно одинаково быстрый, к fms чутка медленне, заметно на глаз
rtmp://domain/app/room1/room2/room3/ тоже не будет работать на fms.
Так, а как мне сравнить цифры через 2 часа с теми, что есть сейчас? Снимаю скриншот, вырезаю из него Task Messenger. Кладу слева скриншот, справа реальный TaskManager. Вот пусть так и лежать, буду поглядывать на них каждые N минут в течение N часов :)
Вы, конечно, скажете, что есть debug console, и что можно мониторить нагрузку на проц и память в реальном времени. Да, можно. Если дебаг-консоль любезно согласится это показать. А то ведь она, зараза, может и не показывать ничего.
Если сервер долго работает под нагрузкой, то рано или поздно случаются сбои. FMS не исключение. Но вот у него нет никаких средств диагностики. Что сломалось? Как исправить? Что сделать, чтобы такое не случалось в будущем? Узнать невозможно. Да, ты можешь напихать кучу трейсов в своем коде, но это не всегда помогает.
Обычно в таких случаях начинается шаманство: перегрузить сервер, удалить shared objects и т.д. На какое-то время это может помочь. До следущего сбоя.
Фигня в общем. Переход на Java (Scala, Groovy) для нас неизбежен...
Схема довольно типичная. Как выяснилось, так оно не только в Mate, но и в PureMVC тоже сделано похоже. Но схема довольно утомительная. Моделей много, методов, которые дергает FMS, тоже много. Кастомные события, карты — overhead.
И тогда пришла в голову мысль как-нибудь сделать так, чтобы сами классы-модели принимали инфу с FMS. На первый взгляд мысль интересная. На второй взгляд — сложно реализуемая. Проблема в том, что для одного NetConnection может быть только один объект, принимающий данные с FMS (FmsClient). Иметь несколько NetConnection нежелательно по ряду причин. В основном потому, что это существенно усложнит логику на стороне сервера (один клиент будет представлен сразу несколькими соединениями).
На третий взгляд мысль все равно интересная и таки реализуемая не очень геморным способом. Надо создавать FmsClient как пустой динамический объект:
netConnection.client = new Object();
Передавать ссылку на этот объект во все модели, а каждая модель примешает к нему те методы, через которые она заинтересована получать данные с FMS.
class MyModel
{
public function init(fmsClient : Object) : void
{
fmsClient.onSomeData = this.onSomeData;
fmsClient.onOtherData = this.onOtherData;
}
}
Выглядит интересно, неприменно попробую на досуге.
Мир жава — статика и строгая типизация. Мир FMS — динамика и замыкания :)
flash_proxy override function callProperty(methodName : , ... args) :
{
this[methodName].apply(this, args);
return null;
}
flash_proxy override function hasProperty(name : *) : Boolean
{ return true; }
flash_proxy override function getProperty(name : ) :
{
return function(... args) : *
{
// NOTE this is same as
//nc.call(methodName, null, args[0], args[1], ..., args[N]);
args.unshift(null);
args.unshift(name);
nc.call.apply(nc, args);
return null;
}
}
Было так:
public function SendMessage(roomID : String, message : MessageVO) : void
{ nc.call('SendMessage', null, roomID, message); }
public function ChangeColor(color : int) : void
{ nc.call('ChangeColor', null, color); }
public function ChangeStatus(status : int) : void
{ nc.call('ChangeStatus', null, status); }
Стало так:
flash_proxy override function callProperty(methodName : , ... args) :
{
// NOTE this is same as
//nc.call(methodName, null, args[0], args[1], ..., args[N]);
args.unshift(null);
args.unshift(methodName);
nc.call.apply(args);
return null;
}
Это работает, пока к FmsService не идут обращения от Mate из EventMap. Оттуда не вызывается callProperty, а вызывается hasProperty и getProperty. Попробовал как-то так:
flash_proxy override function getProperty(name : ) :
{
return function(... args) : *
{
args.unshift(null);
args.unshift(name);
nc.call.apply(args);
return null;
}
}
не работает :(
К сожалению нет времени с этим копаться, попробую в другой раз.
Еще инсталлятор зачем-то предлагает установить apache (видимо для http туннелинга).
А еще в скачано с сайта адоба zip зачем-то лежит экзешник, а все нужное запаковано еще раз в tar.gz
if(G.ClientManager) Core.Error('ClientManager is already exists');
G.ClientManager = {};
G.ClientManager._clients = new Hash();
Две лишние буквы в имени объекта — не смертельно, а мудрить особо нет времени, надо двигаться вперед.
if(ClientManager) Core.Error('ClientManager is already exists');
вылетает с ошибкой.
С ходу придумывается, завести специальный объект для создания области видимости и создавать все остальные объекты в нем (или использовать с той же целью объект Application)
global = {};
if(global.ClientManager) Core.Error('ClientManager is already exists');
global.ClientManager = {};
Но так делать нифига не хочется. Надо что-то получше придумать :(
ClientManager = {};
ClientManager._clients = new Hash();
ClientManager.GetTotal = function()
{
return this._clients.total;
}
Теперь буду создавать так:
if(!ClientManager) Core.Error('ClientManager is already exists');
ClientManager = {};
ClientManager._clients = new Hash();
Вот вызываешь себе ClientManager.GetTotal() а тут бац — нет такого метода в этом объекте. Мистика, отладка, рестратры FMS сервера и другие пляски с бубном.
А оказывается где-то в другом месте кода написано ClientManager = {}
И все, объект обнулен, все его свойства и методы потеряны :)