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

Мой профиль на GITHUB: https://github.com/tirinox

Правда там нужно поработать над описанием, над тестами. Может, написать на тематические ресурсы для пиара.

Сейчас выложены следующий проекты:

Erudite Push Stream

https://github.com/tirinox/erudite_push_stream

Сервер для получения сообщений по TCP от сервера. Пришел из сервера Эрудита. Некоторая замена nginx_push_stream_module. Т. е. у нас есть бэкенд на PHP, он хочет уведомить пользователя о событии, поэтому обращается к erudite_push_stream. Пользователь в свою очередь держит открыт к TCP соединение к нему и получает сообщение.

Написан на Go Lang.

GoWaiter

https://github.com/tirinox/gowaiter

Тоже из инфраструктуры Эрудита. Умеет устанавливать таймеры и дергать HTTP запросы, когда таймер истекает. Так же умеет дергать их заранее заданному расписанию (на подобие CRON). Очень простой сервис с минимумом настроек.

Написан на Go Lang.

 

Я не из тех, кто любит навсегда оставлять прошлое. Я до сих пор считаю, что Лапта достаточно хороша (особенно для дебютного проекта), чтобы уйти в забытие. Поэтому за эти выходные я пересмотрел код, почистил его и отправил обновление.
— Исправление физики
— Повыше динамичность
— Без рекламы
— Без шаринга
— Без промоэффектов
— Частичная поддержка длинных айФонов
Посмотрю на статистику, если еще есть игруны, то будут еще обновления.M5CLez0V8q8

Мне на Новый Год подарили минисервер.
Настоящий сервер! Сделан не в Китае, а в Европе.
Крепкий и надежный корпус. Тяжелый. Дверца на ключе! Винтики и инструменты в комплекте.
Это HP Microserver работает на двухядерном процессоре AMD N54L на частоте 2.2 ГГц.
Изначально в нем было всего 2 Гб оперативной памяти, я тут же добавил еще 4 Гб.
Диск был 250 Гб, пока так и оставил, позже перенесу в него свои объемистые диски, чтобы организовать файлопомойку и торрентокачалку.
Поставил на него Linux Kubuntu: как оказалось серверная Ubuntu – плохая система, а вот декстопная работает на ура!
А так пока использую для тестирования своих серверных приложений: EruditeServer (для пошаговых игр) и OctaveServer (для математических вычислений).

Это чудо стоит всего 8 тыс. руб. в Ситилинке. Сущие копейки! (На самом деле это предыдущее поколении сервера, а актуальное поколение стоит вдвое дороже).
Память обошлась еще в 1300 руб.
Всем брать!

Доволен как слон! Единственный недостаток – он все-таки шумит. Ночью, когда засыпаешь – слышно. Но мне кажется, я стал спать под этот звук даже лучше 🙂

Минисервер в работе

Минисервер в работе

Начал работать над сервером для GNU Octave для лаборатории. Я поискал-поискал и нашел только PHP привязку, причем сам демон сервера тоже на PHP, что не есть хорошо… Поэтому моя идея – сделать сервер на Erlang.

Прототип уже работает. Можно проверить на

telnet dev.erudite-express.ru 20444

 

internal-rfc1918:OctaveServer tirinox$ telnet dev.erudite-express.ru 20444
Trying 195.122.249.19...
Connected to dev.erudite-express.ru.
Escape character is '^]'.
3+2
ans = 5
10-20
ans = -10

Они говорили в LISP много скобок… Да, порой действительно много, но они всегда одинаковые – обычные круглые скобки.

А вот Erlang 🙂

jiffy:encode([{[{<<"a">>,1}]}]).

В одном коротеньком предложении уйма скобок всех возможных видов 🙂

Еще позавчера он нарезал свои самые первые круги по моей комнате, а сегодня на него уже повесили хитровыдуманные датчики и показывают инвесторам. Как же быстро растут дети! 🙂

IMG_2596

Существует официальный баг в Game Center API, когда из списка не удаляется GKTurnBasedMatch. Баг достаточно распространенный, он происходит главным образом тогда, когда активный участник покидает игру (вызов participantQuitInTurnWithOutcome:…) и удаляет ее из своего списка матчей. Игра получает какое-то неверное состояние, после чего остальные игроки не могут ее удалить из списка. Причем не могут как из интерфейса матч-мэйкера, так и вызовом removeWithCompletionHandler:… Возвращается ошибка номер 17 (Error=17) о том, что какие-то параметры заданы неверно. При этом сам матч может иметь уже статус завершенного GKTurnBasedMatchStatusEnded!

Как я уже отметил, Apple призналась в баге, но не исправила до сих пор.

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

Суть в том, чтобы несмотря на завершенность матча попытаться (в случае возникновения ошибки) завершить свой ход, передав его любому другому участнику, затем выйти из игры ВНЕ хода и снова отправить запрос на завершения матча. Этот workaround помог мне со всеми неудаляемыми играми!

Вот код:

- (void) removeGameFromGC
{
 
    [_match removeWithCompletionHandler:
     ^(NSError *error) {
         if(!error)
         {
             DLog(@"match removed!");
         }
         else
         {
             [self reportError:error];
 
             GKTurnBasedParticipant *nextParticipant = nil;
             for (GKTurnBasedParticipant *participant in _match.participants)
             {
                 participant.matchOutcome = GKTurnBasedMatchOutcomeTied;
                 if(![TurnBasedHelper isHeLocal:participant.playerID])
                     nextParticipant = participant;
             }
 
             [_match endTurnWithNextParticipants:@[nextParticipant]
                                     turnTimeout:GKTurnTimeoutDefault
                                       matchData:nil
                               completionHandler:
              ^(NSError *error)
              {
                  if (error)
                  {
                      [self reportError:error];
                  }
 
                  [_match participantQuitOutOfTurnWithOutcome:GKTurnBasedMatchOutcomeQuit
                                        withCompletionHandler:
                   ^(NSError *error)
                   {
                       if (error)
                       {
                           [self reportError:error];
                       }
                       [_match removeWithCompletionHandler:^(NSError *error)
                        {
                            if (error)
                            {
                                [self reportError:error];
                            }
                        }];
                   }];
              }];
         }
 
     }];
}