Веселый мир веселого юникода

Некоторое время назад случайно наткнулся на еще одну проблему с jabber-сервером: зарегистрировавшийся у меня пользователь подключался к конференции индонезийцев на jabber.ru и при попытке сохранить ее в закладки сервер вываливал в логи exception о том, что у меня “Incorrect string value” для таблицы “pubsub_item”.

Строка выглядела как <conference name=''!! \x{1F493}\x{1F49E} Cinta \x{2764}||\x{1F498} Conference \x{1F48C}'' jid=''cinta@conference.jabber.ru'' autojoin=''true''><nick>FF-d</nick></conference> – в реальном мире это выглядело в виде сердечек и прочих забавных смайликов:

Честно говоря, не было на тот момент идей, как это все решить – думал, какой-то баг в ejabberd’e, всплывший из-за плохой проверки строк. Правда, проверил на аккаунте на jabber.ru и попросил еще знакомых с другого сервера проверить – там все добавлялось в закладки нормально, но и версия сервера, и его обвязка отличались от моих. На тот момент так все и оставил – хотя индонезиец попался настройчивый и на момент обнаружения бага я выловил около 50 эксепшнов в логе.

Недавно решал другую проблему – на этот раз с RSS-транспортом, копию которого развернули на сервере captflint.com. Несмотря на прекрасную работу на моих серверах, на captflint’е постоянно вылазили какие-то проблемы. Попутно нашел несколько косяков с логикой скрипта, но основная проблема была с кодировкой. Как выяснилось, у сервера касательно базы были довольно кривые дефолты – база была в utf8, подключение – с latin1 и так далее. В процессе пришлось слить дамп уже созданных лент со старыми настройками, поправить настройки и залить дамп обратно, убрав из него все упоминания latin1 – по-другому не выходило. Честно говоря, не думал, что в 2022 году еще могут возникать подобные проблемы – уже давно везде юникод.

Стало получше, но не до конца – иногда все же всплывали какие-то непонятные косяки с руганью на кодировку. Была поднята тема указания кодировки при старте – в итоге в процессе поисков выяснил, что у MySQLdb есть специальные параметры для использования юникода – причем, по ссылке это находится не в самом топовом ответе. Так или иначе, решил отталкиваться от такого варианта. Правда, все возвращаемые ответы теперь были юникодными объектами – и, что примечательно, такой режим дефолтен для Python3, так что стало еще больше причин сместить код в транспорте в сторону работы с юникодом.

Попутно пришлось немного подтянуть свои знания касательно кодировок в базе и юникода в целом. То, что юникод бывает разных версий (не говоря уж про разные типы) я уже знал давно, но сталкиваться с этим не приходилось. Установленный еще с давних времен “SET NAMES utf8” надолго решил все вопросы по работе с кодировками в базе. Сейчас на глаза чаще стал попадаться utf8mb4, ушел читать про него. Нашлось, например, такое:

Отлично и доступно написанный ответ. В итоге – привычный мне utf8 – алиас для utf8mb3 – юникод с переменной длиной числа байт (и до трех). На сейчас развелось много всяких-разных новых символов в юникоде – эмоджи и тому подобное, что потребовало расширения длины символа до 4 байт. И тут-то при упоминании эмоджи мне и вспомнился мой ejabberd с его проблемой с сохранением закладки на индонезийскую конференцию. Проверил – да, везде utf8. Из ссылки выше попутно вычитал и про разницу general/unicode + ci/cs. В итоге решил актуализировать как настройки в базе, так и базу ejabberd’а и использовать везде utf8mb4_unicode_ci. Тут пригодилась другая статья:

Дальше – небольшой однострочник, который обошел все таблицы и сконвертировал их в новый формат. Проверил – да, проблема с ejabberd’ом ушла, теперь можно в названия конференций запихивать любые смайлики. И вот только что подумал – ведь, фактически, раньше даже сообщение в базу не могло записаться с таким смайликом? Т.е., пересылаться оно пересылалось, а подгрузить с сервера его уже было нельзя.

А транспорт сейчас вполне успешно работает в новом варианте, вроде пока новых проблем не возникало.

Добавить комментарий