Веб-Преферанс на Python

    Не первое десятилетие продолжается спор между архитекторами настольных приложений на предмет, какой же подход, statefull или stateless, более предпочтителен, и в каких случаях.
    Сейчас мы наблюдаем определенный тренд сдачи позиций апологетами statefull. Не в последнюю очередь в этом виноват даже не столько web, сколько банальный HTTP, вполне заслуженно занявший нишу «универсального протокола для всего». Причем возможность передачи Cookie весьма слабо влияет на его насквозь stateless природу.

    Но что HTTP может нам предложить, в случае необходимости создания интерактивного приложения на вебе? Для того чтобы достичь «реактивности» оффлайнового statefull приложения, классического варианта с постоянным опросом состояния сервера короткими AJAX запросами по таймеру явно недостаточно. HTML5 несет нам технологию WebSockets, призванную решить эту проблему. Но ведь нужно чтобы работало «здесь и сейчас» на всех браузерах выпущенных в текущем тысячелетии.

    На помощь приходит технология Comet, при помощи которой мы предприняли попытку реализовать браузерный русский преферанс с мгновенной реакцией на события.

    Итак, знакомьтесь. Клуб интеллектуальных игр «Трельяж»
    trellis-club.com

    Трельяж


    Выбор фреймворка


    На роль низкоуровневой асинхронной библиотеки для проекта проходили кастинг два кандидата.
    Twisted и Tornado. У обоих есть свои плюсы и минусы, по совокупности которых победил Tornado. Он значитаельно уступает своему оппоненту в фичасточти, и что самое неприятное, не умеет «из коробки» делать асинхронные запросы к базе, но… вменяемые html-шаблоны, диспетчеры ресурсов, встроенные средства авторизации на openid серверах, впечатляющая производительность, очень удобный и простой интерфейс для прикладного программиста перевесили чашу на другую сторону.

    Проблема с количеством одновременно открытых соединений


    Глядя на простые и понятные примеры из поставки Tornado, становится понятно как очень быстро писать интерактивные вещи вроде простейшего чата. Так и хочется сразу сделать несколько независимых соединений слушающих разные типы событий. Но, к сожалению, реальность такова, что такая схема не работает. Виной тому старые браузеры не умеющие обрабатывать более двух AJAX запросов одновременно.

    Иными словами, если мы хотим сделать что-то более сложное чем банальный чат, нам придется придумать и реализовать свой высокоуровневый протокол доставки сообщений, работающий поверх JSON.

    Авторизация и Аутентификация


    Начинающие разработчики часто путают эти два понятия. Но между ними есть принципиальная разница. Грубо говоря, аутентификация это процедура определения тот ли это пользователь за кого себя выдает, а авторизация, соответственно, процедура наделения теми или иными правами пользователя, уже прошедшего процедуру аутентификации.

    В текущей версии сервера авторизация упразднена за ненадобностью. Все игроки равны и не делятся на какие-либо классы.

    Аутентификация полностью отдана на откуп OpenID протоколу. В состав tornado входят классы аутентификации через Facebook, Gmail, и другими популярными сервисами. Нет никаких проблем дописать доступ к аутентификационным сервисам того же LiveJournal.

    Помимо упрощения входа для игроков (утомительная процедура регистрации с придумыванием паролей, и подтверждения email попросту становится не нужна), такая схема более безопасна для игроков. Администрация не будет знать никаких паролей игроков, и в то же время серверу не грозят нашествия анонимов-вандалов.

    Игровой цикл


    Общая схема такова. Интерактивная страница делает «долгий» AJAX запрос. Сервер для каждого игрового стола держит пул этих запросов и ждет событий. Событием может быть что угодно. Игрок нажал на карту, написал сообщение в чат, произошел таймаут, изменился счет пули, и т. д. При поступлении события в очередь, сервер закрывает соединения всех слушателей с ответом что именно произошло. Клиентская страница принимает сообщение и решает что делать дальше. Она может взять данные из сообщения и перерисовать какие-то свои части, может сделать «короткий» AJAX запрос дополнительных данных, может сделать редирект на другую страницу, но в конце-концов она опять посылает «долгий» AJAX запрос который ждет следующего события, и цикл возобновляется.

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

    Веб-сайт


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

    Учитывая, что при такой организации сайт имеет доступ ко всем оперативным кешам сервера (включая кеши игроков в онлайне), это дает определенные преимущества в производительности и максимально упрощает задачу программирования функциональности сайта.

    База данных


    В однопоточных неблокирующих серверах очень важно, чтобы не было длительных синхронных операций при генерации ответа. Соединение с базой данных и синхронное ожидание выполнения SQL-запросов очень дорогая по времени операция.

    Обычно это обходят использованием асинхронных запросов к базе. Из популярных драйверов такой режим работы поддерживает, например, psycopg2. Можно пойти дальше и воспользоваться услугами «взрослых» ОРМ вроде SQL Alchemy, которые могут добавить слой асинхронности для практически любого драйвера.

    Альтернативой является использование базы данных по минимуму. Игровые процессы целиком происходят в памяти сервера. Вся статистика для просмотра кешируется везде где только можно. В базу информация о сыгранной партии сбрасывается после расчета только один раз. Сессии в общепринятом понимании веб-приложений в базе вообще не нужны при данной модели построения сервера. Главная страница веб-сайта не создает ни единого sql запроса. Все берется из оперативных кешей.

    Таким образом мы сохраняем простоту синхронного программирования, уменьшаем список зависимостей, и дополнительным бонусом идет защита от DDOS. Запросы от незалогиненных игроков в принципе не имеют доступа к ресурсам, способным генерировать SQL запросы.

    Общие данные


    Помимо оперативных данных каждого стола, на сервере хранятся данные, которые должны быть доступны из любого модуля. Это, например, общий список игроков в онлайне, кеши последних просмотренных игр, пул базы данных, и прочее. Данные такого рода собраны в один модуль. Казалось бы вот оно. Наконец-то паттерн Singleton найдет хоть какое-то применение. Но не все так просто. Во-первых — внутри сервера активно используются таймауты из системного модуля threading. А это значит что все наши кеши обязаны быть потокобезопасными. То есть вызовы меняющие их содержимое придется оборачивать в безопасные секции. С другой стороны, нам нужен простой в использовании режим тестов, в котором модуль общих данных должен работать совсем по другому. Поэтому Singleton уходит туда где ему самое место, и на его позицию приходит Facade.

    Таймауты


    Система таймаутов существенно упрощена по сравнению с существующими нативными клиентами. Игрок нажимает кнопку «накрыть стол» При этом стол сразу переходит в состояние «конвенции». Всем игрокам, находящимся в этой комнате посылается соответствующее сообщение, и они сразу видят что статус стола изменился. У накрывающего, средствами jquery-ui, появляется диалоговое окно, в котором он может выбрать игровые конвенции и сверху тикает таймер. По умолчанию 2 минуты. Если за это накрывающий так и не решил во что именно он хочет сыграть, окно закрывается и стол возвращается в статус «свободен» без каких-либо последствий для игрока.

    После того как стол создан, он переходит в режим бесконечного ожидания игроков. Игроки могут подходить к столу, смотреть конвенции, садиться за стол, вставать из-за стола (при этом место освобождается). Если из-за стола встал последний игрок то стол полностью освобождается, и на нем можно накрыть на другую игру.

    Но как только за стол сел последний игрок (третий или четветрый, в зависимости от того на скольких человек накрыт стол), игра начинается сразу без каких-либо предупреждений. На любое действие игрока отведено определенное время (его количество определяет накрывающий на стол. по умолчанию 5 минут). Если игрок отошел или очень долго думает, он штрафуется и игра закрывается. Никаких режимов ожидания игрока или переносов партии в текущей версии сервера не предусмотрено. Любые проблемы со связью или со временем целиком лежат на плечах игрока, который должен походить в свою очередь во что бы то ни стало.

    Любители нечестной игры


    Единственное ограничение звучит так: Один и тот-же игрок не может сесть за один стол дважды. Больше ограничений нет. Если он успевает играть за двумя, и более столами одновременно, то это его право.

    Широко известная в узких кругах «проблема налапа» техническими средствами не решается (кому надо, знают и про анонимные прокси, и поднять несколько виртуальных машин для них не проблема). В этом случае очень важна деанонимность, аудит, система отзывов и рейтинга игроков. Когда вы играете не с обезличенными никами, а с реальными людьми, у которых есть имя и фамилия (предоставляемые open-id consumer, и поменять их на сервере невозможно), то в этом плане все становится намного проще.

    Что дальше?


    На данный момент сервер находится в статусе BETA-тестирования.
    Расположен по адресу trellis-club.com

    Приятной и доcтавляющей игры.

    Similar posts

    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 68

      0
      Хотел затестить
      Но люди тупят
        +8
        Это одно из свойств людей, отличающих их от животных
          +8
          Животные тоже тупят. Моя кошка тому подтверждение. :)
        +1
        гостинная — это круто
          0
          спасибо :) вторая н уйдет со следующим плановым апдейтом сервера
          0
          Спасибо, недавно как раз занимался подобным :)
            +1
            Хорошая, годная затейка! :) Но ГУИ надо бы подтянуть. Для меня в этом плане идеалом считается интерфейс программы Марьяж.
              0
              Сейчас это все еще глубокая бета, на которой обкатывается ядро. Насчет ГУИ — конечно, тут будут привлекаться профессиональные дизайнеры и «юзабилисты»
              0
              Хорошая игра, но игроков как то мало… Я ожидал хаброэффект, а 7 человек совсем не претендуют на это звание.
              А вообще (не сочтите рекламой) для меня стандартом вэб преферанса является www.gambler.ru/
                0
                Дело в том, что клиент гамблера это standalone java application. А это как-раз то, от чего хочется уйти, чтобы иметь возможность играть anywhere на всем, на чем есть браузер.
                  0
                  Ну можно по крайней мере подсмотреть немного как сделано у них и взять кое-что полезное :). Все-таки гамблеру уже лет 8 не меньше если не ошибаюсь, так что они думаю много костылей повидали )
                    0
                    С 1998 года. :-)
                0
                О! Вечерком поиграю! ;)
                  +1
                  Возникают ли проблемы с утечкой памяти?
                  Что произойдет с игрой, если вдруг упадет игровой демон?
                  Я так понимаю, восстановить ее состояние невозможно?
                    0
                    У 100 одновременно активно играющих игроков в онлайне, и заполненных кешах по статистике игр, потребление памяти в районе 25Mb RES. Утечек явных (не собираемых GC) пока не замечено.
                    ОС — FreeBSD. реактор — kqueue. WCPU для тех же 100 игроков в районе 0.15% на довольно посредственном железе.
                    То есть запас довольно большой.

                    Можно конечно сказать мол «наши демоны никогда не падают», но понятно, что в реальной жизни бывает всякое.
                    При теоретически возможном падении (еще пока что не падало ни разу) высокоуровневый обработчик исключений _попытается_ закрыть и сбросить в базу все текущие игры.
                    –2
                    Попробовал поиграть. Наблюдается небольшая недоработка. Если играющий предлагает сколько он берет то карты его не высвечиваются вистующим :) Надо бы пофиксить ;-)
                      +2
                      К чёрту детали! Спасибо за openID аутентификацию и веб интерйейс. Как раз то, что нужно. А то под Линуксом жуткими костылями ставил windows версии программы «Марьяж». Плюсую во все стороны и в закладки.
                        +1
                        Google != OpenID
                        Если нажать на кнопку авторизации, появляется окно входа в гуглосервисы.
                        А как авторизоваться по OpenID у какого-то другого провайдера?
                          0
                          В ближайшее время дополнительно появятся кнопки авторизоваться через «yandex», «facebook», «livejournal».
                          авторизация у _произвольного_ OpenID чревата побочными социальными эффектами и пока что не планируется
                            0
                            А можно кратенький ликбез — меня напрягла надпись «rellis-club.com запрашивает информацию из вашего аккаунта Аккаунт Google»
                            Мой логин-пароль проходят через вас, или гугль сам сообщает типа «ок, пусти его, я его проверил»?
                              +1
                              именно так. «гугль сам сообщает типа «ок, пусти его, я его проверил»»
                              trellis-club.com никогда не узнает ваших паролей.
                              В этом весь смысл openid. И это абсолютно для вас безопасно.
                          0
                          Пока, к сожалению, не особо поиграешь
                          2 раза попытался создать игру (один раз дошло до торговли), и меня выкинуло без всяких объяснений.
                            0
                            Скорей всего вас не выкинуло (там кстати можно безболезненно опять подойти к столу)
                            Просто есть такой баг что при потере фокуса в поле ввода сообщения в чате кнопка backspace cрабатывает как BACK в браузере.
                              –1
                              К сожалению, скриншотами не располагаю, но именно выкинуло, т.к. все столы в той комнате обнулились и обратно войти я не смог.

                              Попробую на досуге еще раз.
                            +9
                            Кстати масти есть в шрифтах, так что не обязательно их вставлять картинками: ♠♣♥♦
                              0
                              Раз уж «Корректная работа под любыми современными браузерами.», то в Safari под Windows не работает ссылка, показывающая окно со списком игроков онлайн.
                              И еще… Название проекта явно предполагает не только преферанс. «Тысячу» не планируете?
                                0
                                Ссылку поправим. Спасибо.
                                «Тысяча» — возможно, но не сразу. Второй игрой в клубе будут «шахматы»
                                0
                                А точно comet? Я тут с фарбагом к вам залез — вроде как long polling?
                                  +1
                                  википедия утверждает что это (в определенном смысле) одно и то же
                                  en.wikipedia.org/wiki/Comet_%28programming%29
                                  However in practice, Comet applications typically use Ajax with long polling to detect new information on the server
                                    0
                                    Википедия в данном случае неправа, это уже обсасывали, когда dk_multiplexor вышел.
                                      0
                                      Comet — это общее название всех техник создания псевдоасинхронных и псевдомоментальных AJAX.
                                    +1
                                    Comet это скорее принцип, а long polling или persistent connection это уже техника.
                                    0
                                    Нужна кнопка «Быстро начать игру», чтобы сесть за стол где уже есть два игрока.

                                    Не смог сыграть ни разу больше круга — после первой не сложившейся партии выкидывает из любого стола, из-за того что в предыдущей игре у какого-то игрока таймаут.

                                      0
                                      Очень хочется видеть:
                                      1) возможность посмотреть конвенции во время игры
                                      2) времени (как партии так и глобального)
                                      3) просмотр предыдущего расклада
                                        +1
                                        Присоединюсь и добавлю:
                                        4) Хочется пообщаться с игроками по окончании партии, но из-за стола силком выволакивают. Может в окошке с окончательным рассчетом можно оставить чат?
                                        5) Набирал что-то в чате, вылезло окошко с предложением «Пас-Вист» и перехватило фокус, я в это время жмакнул на пробел и пасанул. Хорошо не десятерную заказал.
                                        0
                                        играли мизер, сильно не хватает кнопки «Предложить». пришлось шлепать до конца, хотя сразу было видно что он не ловленый
                                          0
                                          Играли мизер, сошлись на мнении, играющий предложил, все согласились. Так что все есть
                                            0
                                            хм… видимо не заметил у себя такой кнопки. в следующий раз буду внимательнее.
                                            0
                                            Почему-то предложить может только играющий
                                            0
                                            Слово «гостиная» с одной «н» пишется. Поправьте, пожалуйста, а то бьёт по глазам.
                                              0
                                              Уже поправили. Спасибо. Также добрые хабралюди нашли еще несколько проблем, которые либо уже исправлены, либо будут исправлены в течении суток.
                                              Но все это вступит в силу только с плановым обновлением сервера. (через 2 дня)
                                              0
                                              При торговле при нажатии клавиш или проблема происходит автоматический выбор чего-то. А случается это часто, если писать в чате.

                                              Иногда окошки «выскакивают» в нескольких количествах. Разные притом.
                                                0
                                                пробел при писанине во время торгов подводит (
                                                вступаешь в торг, часто нежелательный совсем
                                                  0
                                                  Кажется баг — не пишет висты при предложении
                                                    0
                                                    Периодически выкидывает из игры с сообщением «не проявляете активности»
                                                    Не расчитываются висты в случае, если игра заканчивается приедложением, на которое все соглашаются
                                                      0
                                                      А вообще — вы молодец. Отличный старт, как чисто технический, так и вцелом проект. Буду с интересом наблюдать за развитием.
                                                        0
                                                        Спасибо за добрые слова.
                                                        Клятвенно обещаю что такого позора, который был исправлен в этом changeset больше не повторится :)
                                                        trac.trellis-club.com/changeset/121%3A405e570b3940
                                                          0
                                                          Может быть я вас и удивлю, но у меня очепятки в интерфейсе — одна из самых казалось бы мелких, но очень досадных проблем при разработке.
                                                      0
                                                      Интересно. Я делаю почти то же самое — мультиплеерный «Сапёр» (sweepminer.com).

                                                      Пробовал использовать Juggernaut, в нем вместо Комета используется невидимый флэш, который держит соединение с сервером. Не понравилось, перешел на Orbited + Morbidq. Теперь нет проблем у тех, кто сидит за прокси.

                                                      Для авторизации выбрал только Facebook Connect, из Фейсбука же и беру аватарки игроков.
                                                        0
                                                        Супер!
                                                        Как раз думал над такой игрой! Жаль, что пока там никого :(
                                                        У вас какие правила мультиплеера?
                                                          0
                                                          Кто-то есть:)

                                                          Правила сейчас такие: игра идет на одном поле, чужие поставленные флажки не видно. Но видно клетки, раскрытые другими участниками. Побеждает тот, кто первым правильно расставит все свои флажки. За каждую раскрытую клетку дается очко — тому, кто ее раскрыл.

                                                          Но я хочу придумать что-то другое. Проблема в том, что сейчас игроки идут ноздря к ноздре всю игру, и интрига возникает только в последние три секунды матча — кто же первым поставит последний флажок. Надо сделать так, чтобы на победу влияло, сколько очков за игру набрал участник, а не только то, что он первым поставил флажки.
                                                            0
                                                            Обычно народ ближе к вечеру собирается поиграть.
                                                            При хабраэффекте одновременно играли 150 человек.
                                                            Проблем все еще много. Но ежедневно выходят новые фиксы,
                                                            выравнивающие положение.
                                                            Правила преферанса обычные (из кодекса)
                                                          0
                                                          Сколько времени ушло на разработку? Сколько человек принимало участие (если таковые были крме вас)? Было бы интересно увидеть roadmap.
                                                            0
                                                            полгода.
                                                            roadmap — пишем.
                                                              0
                                                              Сколько человек, кроме вас, работают над проектом? Что делают?
                                                                0
                                                                По history на trac нетрудно догадаться что до сегодняшнего дня ни одного.
                                                                Но в данном случае это неважно. Главное то, что проект будет развиваться.
                                                                И развиваться динамично. Сегодняшний тест добрых хабралюдей направил
                                                                приоритеты задач в нужное русло.
                                                                И хотя сервер под хабраэффектом не падал,
                                                                проблемы выявились серьезные но вполне решаемые.
                                                                  0
                                                                  А кого-нибудь не хватает? Дизайнера, пиарщика, верстальщика, тестера, еще одного программиста?
                                                                    0
                                                                    Не хватает _хорошего_ дизайнера/юзабилиста который создаст стиль проекту
                                                            0
                                                            а как можно получить сам код, чтобы с удобством в нем разобраться или дописать что-либо?
                                                            я так понимаю там hg. есть анонимный доступ на чтение в репозиторий?
                                                              0
                                                              Нет. Анонимного доступа в репозиторий нет и не будет.
                                                              Максимум что есть (и так и останется) — браузинг всех исходников через web.
                                                              НО. После обкатки API будет фриз ядра, и независимые разработчики смогут писать
                                                              свои игры под эту платформу (преферанс — только первая игра, но будут и другие).
                                                              Вот у них, необходимый доступ будет
                                                                0
                                                                понимаю. но какой в этом смысл?
                                                                код по сути-то открыт, но легкого доступа нет. Т.е. особо упорный все одно достанет, ведь так? уж лучше открыть read-only доступ, так удобнее разбираться в архитектуре, чтобы приобщиться впоследствии к написанию-развитию.

                                                                да, и странно, почему вы отказались от websocket, если есть js-либы, которые его эмулируют для старых браузеров. ну или на худой конец AMQP-сервер, для надежности и скорости.

                                                                  0
                                                                  Упорный все достанет, но это не будет иметь особого смысла просто потому, что апдейты частые
                                                                  и код очень быстро устаревает. (совсем упорные конечно напишут парсер но это уже будет overq)
                                                                  Но с другой стороны всегда можно пойти и посмотреть как именно сделаны те или иные части
                                                                  но форкать сам проект затруднительно. И это сделано намеренно.

                                                                  Насчет WebSockets и AMPQ. Думали над обоими словами.
                                                                  Пришли к выводу что не стОит. По многим причинам.

                                                                    +1
                                                                    а насчет WebSocket и AMPQ можно подробнее? Чем не устроили?
                                                                    Или просто хотелось Tornado задействовать?
                                                                      0
                                                                      Расскажите, плз, по каким соображениям отказались от WebSockets и AMQP.
                                                                0
                                                                Так и не понял, как решается проблема с количеством одновременно открытых соединений? Расскажите пожалуйста подробнее.
                                                                  0
                                                                  Никак не решается. Соединение в один момент времени только одно.
                                                                  Но по нему приходят все типы сообщений
                                                                  Делать по другому — значит отказаться от значительной доли браузеров
                                                                    0
                                                                    Т.е. на каждого пользователя висит по одному соединению с большим таймаутом? Как к этому отнесется сервер, когда пользователей будут тысячи?
                                                                      0
                                                                      TornadoServer — Хорошо отнесется. Он под такую модель использования и заточен.

                                                                Only users with full accounts can post comments. Log in, please.