Codeigniter Routes regex - использование тире в именах контроллеров / методов

Как мне вызвать функцию или как ее обернуть, чтобы, если она занимает больше 5 секунд, скрипт отменяет ее?

Я отправил gist , который решает этот вопрос / проблему с декоратором и threading.Timer. Здесь он с разбивкой.

Импорт и настройки для совместимости

Он был протестирован с Python 2 и 3. Он также должен работать под Unix / Linux и Windows.

Сначала импорт. Эти попытки сохранить код совместимым независимо от версии Python:

from __future__ import print_function
import sys
import threading
from time import sleep
try:
    import thread
except ImportError:
    import _thread as thread

Использовать независимый от версии код:

try:
    range, _print = xrange, print
    def print(*args, **kwargs): 
        flush = kwargs.pop('flush', False)
        _print(*args, **kwargs)
        if flush:
            kwargs.get('file', sys.stdout).flush()            
except NameError:
    pass

Теперь мы импортировали наши функции из стандартной библиотеки.

exit_after decorator

Далее нам нужна функция для завершения main() из дочернего потока:

def quit_function(fn_name):
    # print to stderr, unbuffered in Python 2.
    print('{0} took too long'.format(fn_name), file=sys.stderr)
    sys.stderr.flush() # Python 3 stderr is likely buffered.
    thread.interrupt_main() # raises KeyboardInterrupt

И вот сам декоратор :

def exit_after(s):
    '''
    use as decorator to exit process if 
    function takes longer than s seconds
    '''
    def outer(fn):
        def inner(*args, **kwargs):
            timer = threading.Timer(s, quit_function, args=[fn.__name__])
            timer.start()
            try:
                result = fn(*args, **kwargs)
            finally:
                timer.cancel()
            return result
        return inner
    return outer

Использование

И вот использование, которое напрямую отвечает на ваш вопрос об окончании через 5 секунд!:

@exit_after(5)
def countdown(n):
    print('countdown started', flush=True)
    for i in range(n, -1, -1):
        print(i, end=', ', flush=True)
        sleep(1)
    print('countdown finished')

Демонстрация:

>>> countdown(3)
countdown started
3, 2, 1, 0, countdown finished
>>> countdown(10)
countdown started
10, 9, 8, 7, 6, countdown took too long
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 11, in inner
  File "", line 6, in countdown
KeyboardInterrupt

Второй вызов функции не будет завершен, вместо этого процесс должен выйти с трассировкой!

KeyboardInterrupt не всегда останавливает спальный поток

Обратите внимание, что спящий режим не всегда прерывается прерыванием клавиатуры на Python 2 в Windows, например:

@exit_after(1)
def sleep10():
    sleep(10)
    print('slept 10 seconds')

>>> sleep10()
sleep10 took too long         # Note that it hangs here about 9 more seconds
Traceback (most recent call last):
  File "", line 1, in 
  File "", line 11, in inner
  File "", line 3, in sleep10
KeyboardInterrupt

, и он не может прервать работу кода в расширениях, если он явно не проверяет наличие PyErr_CheckSignals(), см. Cython, Python и KeyboardInterrupt игнорируются

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

] Как мне вызвать функцию или как ее обернуть, чтобы, если она занимает больше 5 секунд, скрипт отменяет ее и делает Что-то еще?

Чтобы поймать его и сделать что-то еще, вы можете поймать KeyboardInterrupt.

>>> try:
...     countdown(10)
... except KeyboardInterrupt:
...     print('do something else')
... 
countdown started
10, 9, 8, 7, 6, countdown took too long
do something else
25
задан DisgruntledGoat 3 October 2011 в 23:33
поделиться

4 ответа

Это в точности мое требование, и я использовал маршруты типа

$route['logued/presse-access'] = "logued/presse_access";

В моем предыдущем проекте мне нужно было создать 300-400 правил маршрутизации, большинство из них связано с преобразованием черточки в подчеркивание.

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

Убедитесь, что префикс subclass_prefix имеет следующий вид в вашей системе / application / config / config.php

$config['subclass_prefix'] = 'MY_';

Затем загрузите файл с именем MY_Router.php в каталог system / application / libraries.

<?php

class MY_Router extends CI_Router { 
    function set_class($class) 
    {
        //$this->class = $class;
        $this->class = str_replace('-', '_', $class);
        //echo 'class:'.$this->class;
    }

    function set_method($method) 
    {
//      $this->method = $method;
        $this->method = str_replace('-', '_', $method);
    }

    function _validate_request($segments)
    {
        // Does the requested controller exist in the root folder?
        if (file_exists(APPPATH.'controllers/'.str_replace('-', '_', $segments[0]).EXT))
        {
            return $segments;
        }
        // Is the controller in a sub-folder?
        if (is_dir(APPPATH.'controllers/'.$segments[0]))
        {       
            // Set the directory and remove it from the segment array
            $this->set_directory($segments[0]);
            $segments = array_slice($segments, 1);

            if (count($segments) > 0)
            {
                // Does the requested controller exist in the sub-folder?
                if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().str_replace('-', '_', $segments[0]).EXT))
                {
                    show_404($this->fetch_directory().$segments[0]);
                }
            }
            else
            {
                $this->set_class($this->default_controller);
                $this->set_method('index');

                // Does the default controller exist in the sub-folder?
                if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.EXT))
                {
                    $this->directory = '';
                    return array();
                }

            }

            return $segments;
        }

        // Can't find the requested controller...
        show_404($segments[0]);
    }
}

Теперь вы можете свободно использовать URL, например http://example.com/logued/presse-access , и он будет вызывать соответствующий контроллер и функцию, автоматически преобразовывая тире в подчеркивание.

Редактировать: Вот наше решение Codeigniter 2, которое отменяет новые функции CI_Router:

<?php

class MY_Router extends CI_Router { 
    function set_class($class) 
    {
        $this->class = str_replace('-', '_', $class);
    }

    function set_method($method) 
    {
        $this->method = str_replace('-', '_', $method);
    }

    function set_directory($dir) {
        $this->directory = $dir.'/';
    }

    function _validate_request($segments)
    {
        if (count($segments) == 0)
        {
            return $segments;
        }

        // Does the requested controller exist in the root folder?
        if (file_exists(APPPATH.'controllers/'.str_replace('-', '_', $segments[0]).'.php'))
        {
            return $segments;
        }

        // Is the controller in a sub-folder?
        if (is_dir(APPPATH.'controllers/'.$segments[0]))
        {
            // Set the directory and remove it from the segment array
            $this->set_directory($segments[0]);
            $segments = array_slice($segments, 1);


            while(count($segments) > 0 && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0]))
            {
                // Set the directory and remove it from the segment array
                $this->set_directory($this->directory . $segments[0]);
                $segments = array_slice($segments, 1);
            }

            if (count($segments) > 0)
            {
                // Does the requested controller exist in the sub-folder?
                if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().str_replace('-', '_', $segments[0]).'.php'))
                {
                    if ( ! empty($this->routes['404_override']))
                    {
                        $x = explode('/', $this->routes['404_override']);

                        $this->set_directory('');
                        $this->set_class($x[0]);
                        $this->set_method(isset($x[1]) ? $x[1] : 'index');

                        return $x;
                    }
                    else
                    {
                        show_404($this->fetch_directory().$segments[0]);
                    }
                }
            }
            else
            {
                // Is the method being specified in the route?
                if (strpos($this->default_controller, '/') !== FALSE)
                {
                    $x = explode('/', $this->default_controller);

                    $this->set_class($x[0]);
                    $this->set_method($x[1]);
                }
                else
                {
                    $this->set_class($this->default_controller);
                    $this->set_method('index');
                }

                // Does the default controller exist in the sub-folder?
                if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.'.php'))
                {
                    $this->directory = '';
                    return array();
                }

            }

            return $segments;
        }


        // If we've gotten this far it means that the URI does not correlate to a valid
        // controller class.  We will now see if there is an override
        if ( ! empty($this->routes['404_override']))
        {
            $x = explode('/', $this->routes['404_override']);

            $this->set_class($x[0]);
            $this->set_method(isset($x[1]) ? $x[1] : 'index');

            return $x;
        }


        // Nothing else to do at this point but show a 404
        show_404($segments[0]);
    }
}

Теперь нужно поместить этот файл, например application / core / MY_Router.php, и убедиться, что у него есть subclass_prefix определяется как $ config ['subclass_prefix'] = 'MY _'; в application / config / config.php

Несколько дополнительных строк кода было добавлено в метод _validate_request () :

while(count($segments) > 0 && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0]))
{
    // Set the directory and remove it from the segment array
    $this->set_directory($this->directory . $segments[0]);
    $segments = array_slice($segments, 1);
}

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

48
ответ дан 28 November 2019 в 17:51
поделиться

Я не уверен, что вы могли бы сделать это с помощью маршрута ...

Однако где-то в основных библиотеках Codeigniter (возможно, Router или URI) будет что-то, что преобразует подчеркнутые uris в имя класса camelcase.

Я быстро просмотрел и не нашел, но если вы это сделаете, просто скопируйте эту библиотеку в папку вашего приложения / библиотек и измените ее там.

0
ответ дан 28 November 2019 в 17:51
поделиться

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

1
ответ дан 28 November 2019 в 17:51
поделиться
<?php
class MY_Router extends CI_Router
{
 function _set_request($segments = array()) {
  parent::_set_request(str_replace('-', '_', $segments));
 }
}
?>

Поместите этот файл MY_Router.php в / application / libraries (CI1) или / application / core (CI2) Помните, что это повлияет на все сегменты, а не только на модуль, контроллер и метод.

Альтернативой этому расширению является добавление каждого сегмента в router.php. $ route ['this-is-a-module-or-controler'] = 'this_is_a_module_or_controller';

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

3
ответ дан 28 November 2019 в 17:51
поделиться
Другие вопросы по тегам:

Похожие вопросы: