Friday, July 3, 2009

Поддержка entity в XML Parser(PHP)

По-умолчанию xml parser не поддерживает символические имена для спец символов(entity), при парсинге XML в котором встречаются такие символы - они отбрасываются. Для того чтобы этого избежать нужно заменить все символические имена на цифровые коды, которые он нормально обрабатывает.

Примерчик:
...

/* replace some named entity
amp|#38
quot|#34
gt|#62
nbsp|#160
lt|#60
iexcl|#161
cent|#162
pound|#163
copy|#169
*/
function replace_entity($document)
{
$search = array (
"'&'",
"'"'",
"'>'",
"' '",
"'<'",
"'¡'",
"'¢'",
"'£'",
"'©'"
);
$replace = array (
"&",
""",
">",
" ",
"<",
"¡",
"¢",
"£",
"©"
);
return preg_replace($search, $replace, $document);
}

function parse($data, $logs)
{
$this->logfile= $logs;
$this->parser = xml_parser_create('UTF-8');
xml_set_object($this->parser, $this);
xml_parser_set_option($this->parser, XML_OPTION_CASE_FOLDING, false);
xml_set_element_handler($this->parser, 'tag_open', 'tag_close');
xml_set_character_data_handler($this->parser, 'cdata');
$this->log_all($data."\n");
if (!xml_parse($this->parser, $this->replace_entity($data)))
{
$this->error_code = xml_get_error_code($this->parser);
$this->error_string = xml_error_string($this->error_code);
$this->current_line = xml_get_current_line_number($this->parser);
$this->current_column = xml_get_current_column_number($this->parser);
}
xml_parser_free($this->parser);
}
...


P. S. Полгода - год назад это было так, сейчас может быть уже поддерживает, но решение вполне универсально, так как помогает добавить поддержку новых спецсимволов, если это потребуется.

Wednesday, June 24, 2009

Параметры мобильного телефона используя wurfl

Для того чтобы определить параметры мобильного телефона можно использовать 2 пути:
  • определение свойств на основе мобильного профайла возвращенного в заголовках запроса (CC/PP);
  • определение на основе данных переданных в качестве UserAgent.
Первый случай дает возможность сделав несколько запросов на профайл и изменения в нем по протоколу CC/PP получить полные официальные данные об устройстве, но этот случай имеет несколько недостатков, указанный в профайле ресурс может быть недоступен и мы терем время на эти запросы.

Второй позволяет не делать никаких внешних запросов и работать с внутренней базой, но она большая и может содержать не все устройства. В соответствии с новым API можно искать не полное совпадение, что должно несколько уменьшить размер базы, так как нужно найти только похожий, и больше вероятность получить описание мобильного устройства.

Принцип работы с базой wurfl:
  1. найти максимально похоже имя user agent по xpath пути:"/wurfl/devices/device/@user_agent. (В первой версии искалось полное соответствие.)
  2. определить идентификатор этого описания: "/wurfl/devices/device[@user_agent='UserAgent']/@id"
  3. попытаться получить описание нужного нам свойства используя: "/wurfl/devices/device[@id='идентификатор']/group[@id='markup']/capability[@name='html_wi_oma_xhtmlmp_1_0']/@value" . markup - имя группы свойств, html_wi_oma_xhtmlmp_1_0 - свойство.
  4. Если получить не удалось получаем идентификатор подобного устройства: "/wurfl/devices/device[@id='идентификатор']/@fall_back".
  5. Если получить описание устройства не удается через fall_back мы всегда попадем на описание generic устройства, у которого значение всех свойств равно false.
Ссылки:

Wednesday, June 17, 2009

Патчи к gtkhtml

Описание моих патчей к gtkhtml:
  • Get rid of deprecated libgnomecanvas Удалена зависимость от libgnomecanvas (полностью удален bonobo компонент, не устанавливаемый по умолчанию в систему) и переписан код конструирования панелей использовавших bonobo (теперь код использует только функции gtk+). Доступно в версии 3.26.
  • Удаление использования libgnome Замена на использование GtkBuilder для генерации меню и автоматический поиск каталога с тестами. Доступно в версии 3.27.3.
  • Поддержка data URI Добавляет поддержку datauri, также:
  1. исправляет код формирования url на основе относительного и базового url страницы с которой вызывается запрос (теперь в);
  2. добавлена автоматическая замена содержимого при получении, если при вызове получения данных ожидается html, но была получена картинка, автоматически формируется html с ссылкой на эту картинку;
  3. добавлено два вызова для gtkhtmlstream установки базовой страницы и content type для конкретного потока, ранее эти параметры устанавливались для всего документа и он мог отобразиться не корректно.
  • Использование GtkBuilder вместо libglade. Заменяет устаревший(deprecated) libglade на более универсальный код использующий GtkBuilder. (3.07.2009 - применено в основной ветви, будет доступно в следующем релизе).
  • Поддержка cookies - включает поддержку cookies при установленном libsoup версии > 2.26, включается только в тестовом приложении не устанавливаемом в систему. Доступно в версии 3.27.3.
P.S.: поддержка этих изменений в skybrowser я не добавил.
  1. Код со всеми моими изменениями.
  2. Официальный репозиторий.

Friday, June 5, 2009

timeouts in merle

Добавил в мою ветвь кода merle возможность работы с timeout.
  1. В функцию connect новый параметр Options, передаваемый в функцию gen_server:start_link . Этот параметр позволяет установить timeout и включить режим отладки:
  • Options ::= [{timeout, Timeout} | {debug, [Flag]}]
  • Flag ::= trace | log | {logfile, File} | statistics | debug(debug == log && statistics)
  1. В getkeylist(Key, Timeout) добавлен параметр максимального ожидания ответа, предыдущий вариант тоже остался, его поведения также можно эмулировать - указав значение 0
  2. Функция setlist теперь ожидает установки только время указанное как значение времени кеширования (гарантия что. если время кэширования было превышено, сохранение не произойдет). При значении 0 поведение сохраняется, как было до изменения.
Эти изменения позволяют снизить количество одновреммено запущеных запросов к merle во время повышенной нагрузки на систему временем timeout.

Monday, May 25, 2009

Изменил мою ветвь с Merle.

Вернул все файлы которые удалил в своей версии merle. Это нужно для большей совместимости с основной веткой, и возможности обновления с нее с последующим вливанием изменений, если получиться в основную ветвь кода.

Чтобы отключить использование gen_server2 - нужно только переименовать все gen_server2 -> gen_server.

Friday, May 22, 2009

Повышение надежности системы

Повышение надежности предыдущей схемы (используя nginx).

В предыдущей схему существует один потенциально ненадежный элемент backend сервер. При его сбое система через некоторое время утрачивает возможность отрабатывать запросы, так как время кэширования на memcahed заканчивается и все запросы начинают идти на этот сервер. В результате система не может выдать никакого контента пока он не будет перезапущен. Чтобы этого избежать можно дать возможность frontend возвращать данные с просроченным сроком давности, реализовать это на уровне memcached усложняет способ работы с ним:
  • по умолчанию, если закончилось время хранения контент удаляется;
  • и при смене поведения усложняется алгоритм работы с ним из frontend.
В результате наиболее простым методом, если используется в качестве frontend nginx, можно разрешить ему при сбоях использовать собственный кэш (опция proxy_cache_use_stale). Пример:

proxy_cache_path /var/tmp/nginx/cache levels=1:2 keys_zone=one:10m inactive=20m max_size=500m;

server {
listen 80;

location / {
if ( $args = "" ){

set $memcached_key "$uri";
memcached_pass 127.0.0.1:11211;
error_page 404 502 503 504 = @backend;
add_header "Content-Type" "text/html; charset=UTF-8";
add_header "Cache-Control" "max-age=15";
}

proxy_pass http://backend;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header HOST $http_host;
proxy_buffers 8 32k;

proxy_cache_key "$scheme://$host$uri$is_args$args:";
proxy_cache one;
proxy_cache_min_uses 1;
proxy_cache_valid 200 30s;
proxy_cache_use_stale error timeout http_500 http_502 http_503;

}

location @backend {
proxy_pass http://backend;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header HOST $http_host;
proxy_buffers 8 32k;

proxy_cache_key "$scheme://$host$uri$is_args$args:";
proxy_cache one;
proxy_cache_min_uses 1;
proxy_cache_valid 200 30s;
proxy_cache_use_stale error timeout http_500 http_502 http_503;
}
...............
В данном случае frontend не обязательно слабое звено - его можно продублировать с меньшими затратами по сравнению с дублированием backend + slaveDB.

Thursday, May 21, 2009

Код корректного перезапуска merle

При использование кода связи с memcached возможен случай когда соединение с memcached по каким-то причинам потеряно, например: рестарт memcached.
  • В данном случае возможен случай когда выполнить вызов не удается, но пересоединение не получается (закрытие (disconnect) сообщает - что закрывать нечего, а открытие (connect) сообщает - что уже есть соединение). В данном случае нужно убить это псевдо-рабочее соединение и запустить наново.
  • Другой случай когда соединяться не с кем - тогда метод connect просто выходит, не вызывая исключение, что очень плохо, так как не понятно, что произошло с системой - чтобы отловить эту ситуацию нужно разрешить посылку сигнала о завершении потока и ожидать получение этого сообщения.
Пример кода:

%%use with restart
try_with_restart(LU, F) ->
try
F()
catch
Sub : Reson ->
debug_log(LU, "Start procedure restart connect:~p~n",[{Sub,erlang:get_stacktrace(),Reson}]),
spawn(fun() ->
process_flag(trap_exit, true),
Connect = merle:connect(?MEMCACHED_HOST,?MEMCACHED_PORT),
case Connect of
{error, {already_started, Client}} ->
debug_log(LU, "try kill client status:~p~n",[Connect]),
exit(Client,kill);
Value ->
debug_log(LU, "Some other error:~p~n",[Value])
end,
receive
{'EXIT', Pid, Why} ->
debug_log(LU, "Me killed~p~n", [{Pid, Why}])
end
end),
undefined
end.

Примечание:
  1. F - функция обращающаяся к merle;
  2. debug_log() - вывод в логи отладочной информации.