Как стать автором
Обновить

Комментарии 12

НЛО прилетело и опубликовало эту надпись здесь
Чувство вины ни при чем, обычное кармадрочерство :)
Без нее грустно…

А вашу карму где так потрепало? Или это целенаправленное движение к ачивке тролль?

всё зря было, удаляйте о сколько нам открытий чудных...


Добавить yield перед вызовом методов и функций не очень сложно.

но не все yield одинаково полезны. yield сам по себе никакую магию асинхронности не делает, магию асинхронности делает amp, в котором вызывается функция-генератор.
когда вы пишете


Amp\Loop::run(function () {
    yield $promise;
});

внутри функции run происходит примерно следующее (ну если прям совсем на пальцах):


public static function run(callable $callable) 
{
    $generator = $callable();
    if ($generator->valid()) {
        $promise = $generator->current();
        $promise->onResolve(function ($error, $result) use ($generator) {
            if ($error !== null) {
                 return $generator->throw($error);
            }
            return $generator->send($result);
        });
    }
}

то есть за асинхронной функцией на yield должен стоят бекенд, который при yield промиса из этой функции будет дожидаться его и делать send при резолве этого промиса.
это происходит в случае, если вы выбрасываете из генератора промис в
1) контексте генератора, переданного в Loop::run()
2) в контексте генератора, вызванного через call/callAsync
3) в контексте корутины, созданной с помощью coroutine/asyncCoroutine
4) в контексте генератора, переданного в Promise\wait (который под капотом просто вызовет Loop::run())


мало того, вы не можете выбросить с помощью yield что угодно, вы должны выбрасывать инстанс amp или reactphp промиса.
пытаясь, например, сделать


yield unset($storage['index']);

вы выбросите результат выполнения функции unset (а именно null);
и этот код с точки зрения amphp будет эквивалентен


yield null;

на самом деле, учитывая что у вас далеко не самая высокая нагрузка, а доступ к бд осуществляется практически всегда по PK, очень вряд ли вы существенно потеряли бы в производительности, если бы написали просто перегрузку массива на не асинхронном доступе к бд, просто через pdo. а еще лучше — взяли бы что-то более ориентированное на key-value, тот же редис.


вообще madeline, наверное, самое ужасное, что я видел из написанного на php в последние годы, и очень хороший пример, как проект выглядеть не должен. а попытки использования его не as is преврящаются в вот такие костыли, что на самом деле скорее грустно.

Касательно yield все так. Но в процессе написания решил не усложнять этот момент деталями (возможно зря). Благодарю за развернутый коммент, вставлю на него ссылку в посте.
а доступ к бд осуществляется практически всегда по PK
Да, доступ всегда по primary за исключением полного перебора.
учитывая что у вас далеко не самая высокая нагрузка…
MadelineProto у меня крутится на публичном демо tg.i-c-a.su, как часть TelegramApiServer. В рамках одного процесса amphp loop обслуживает еще и amphp/http_server. Не хайлоад, конечно, но 10 одновременных запросов может придти легко. Лишние задержки сильно скажутся на времени ответа.
Кроме того, инстансов madelineProto может быть много внутри одного процесса. И в фоне они постоянно получают апдейты из telegram, которые тоже могут требовать дступа к бд.
Первые версии обновления действительно были частично блокирующими, но решил не «экономить на спичках» во время такого большого pull request.

а еще лучше — взяли бы что-то более ориентированное на key-value, тот же редис
Выбранная архитектура не завязана на конкретную бд. Написать адаптер для redis дело пары часов, и драйвер асинхронный есть. Мне привычнее было начать с mysql. Кроме того, mysql более распространен на shared и бесплатных хостингах. А пользователи активно их используют для madeline.

а попытки использования его не as is преврящаются в вот такие костыли
А что имеется ввиду под использовать, как есть? Не использовать на аккаунтах с большим количеством данных? Или купить vps с 16 gb ram специально под нее? :)
А что имеется ввиду под использовать, как есть?

я имею ввиду, что вот это вот:
Выбранная архитектура не завязана на конкретную бд

по-хорошему должен сделать был danog, предоставив интерфейс работы с хранилищем сессий, и дефолтный драйвер а-ля SessionStorageInterface, который бы работал как сейчас, но была бы возможность писать свои драйверы по-человечески.
в конкретно данном случае это должно быть что-то в духе (опять же, если совсем на пальцах)
interface SessionStorageInterface {
    public function set($key, $value) : \Amp\Promise;
    public function get($key) : \Amp\Promise;
    public function has($key) : \Amp\Promise;
}

с дефолтной заглушкой, а-ля
class ArraySessionStorage implements SessionStorageInterface {
    private $storage = [];
    public function set($key, $value) : \Amp\Promise {
        $this->storage[$key] = $value;
        return new \Amp\Success();
    }

    public function get($key) : \Amp\Promise {
        if (isset($this->storage[$key])) {
            return new \Amp\Success($this->storage[$key]);
        }

        return new \Amp\Failure();
    }

    public function has($key) : \Amp\Promise {
        return isset($this->storage[$key])
            ? new \Amp\Success(true);
            : new \Amp\Success(false);
    }
}


да и вообще сама структура madeline это ужас и боль.
я представляю себе объем работы, который выполнил автор, честь ему и хвала за усидчивость и вложенные силы, но качество проекта очень печальное.
и если стоит вопрос как-то серьезно кастомизировать её под свои нужды, то порой проще будет написать своё.
По поводу unset и прочих встроенных методов. У меня была надежда на то, что unset схематично работает так:

function unset($key) {
    return $this->offsetUnset($key);
}


По факту оказалось так:

function unset($key) {
    $this->offsetUnset($key);
}

Yield становится аналогом async… await из js

До появления async/await в js также строили асинхронный flow через генераторы и yeild. Посмотрите на koa 1, окажется что все очень похоже.
Ну чтож, похоже вы привнесли в серьезный баг в открытый проект — «небезопасная десериализация в пхп»
Не представляю, каким образом можно заэксплоитить. В базу пишется кэш мета данных из телеграм, а не пользовательский ввод.

Ну теоретически в свой username/имя можно попробовать запихнуть какую то вредоносную строку и тогда другой аккаунт в madelineProto сериализует эту строку в базу. Но опять же, как эксплуатировать это?
Быстрый поиск показал к примеру вот этот класс — github.com/xtrime-ru/MadelineProto/blob/master/src/danog/MadelineProto/Logger.php, который можно вызвать через github.com/xtrime-ru/MadelineProto/blob/master/src/danog/MadelineProto/MTProto.php#L925. Особо интересна эта строка github.com/xtrime-ru/MadelineProto/blob/master/src/danog/MadelineProto/Logger.php#L205, которая удаляет лог файлы на сервере на основе переданных настроек.
А вообще, если даже сейчас нет уязвимых классов, они могут появится в будущем. Не в этом репозитории так в любой композер зависимости.

В общем, сериализировать юзер инпут — зло. Лучше заменить на json.
сериализировать юзер инпут — зло


Благодарю за развернутый комент, но о каком вводе идет речь? Это демон, работающий в cli. Данные он принимает только от telegram.
Вы же сами упомянули имя пользователя, что является пользовательским вводом.
На канал к боту заходит такой пользователь и автоматом выполняется какой-то нежелательный код на сервере.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории