Web Фреймворк по-японски — Amon2



    INTRO

    В интервью японца Tokuhiro Matsuno прозвучала следующая фраза:
    «Некоторыми приложениями нашей компании пользуются более миллиона человек. Все это работает на Amon2


    Я не нашел на русском языке никакой инфы об этом веб фреймворке. И решил попробовать, что это за Amon2, чисто для себя, и, может быть, кому-то это будет интересно.



    Установка.


    Под руку попалась виртуалка с Debian GNU/Linux 7.3 (wheezy)
    Поехали…

    # curl -L http://cpanmin.us | perl - Amon2
    ................
    Building and testing Amon2-6.00 ... OK
    Successfully installed Amon2-6.00
    78 distributions installed
     Successfully installed Amon2-6.00
    

    Все! Установка завершена.

    Из коробки мы получили:


    Создание каркаса



    adduser dotcloud
    su - dotcloud
    amon2-setup.pl BBS
    


    Все идет хорошо, пока ...
    — Running flavor: Basic — [main] Loading asset: jQuery
    [main] Loading asset: Bootstrap
    [main] Loading asset: ES5Shim
    [main] Loading asset: MicroTemplateJS
    [main] Loading asset: StrftimeJS
    [main] Loading asset: SprintfJS
    [main] Loading asset: MicroLocationJS
    [main] Loading asset: MicroDispatcherJS
    [main] Loading asset: XSRFTokenJS
    [Flavor::Basic] writing tmpl/index.tx
    [Flavor::Basic] writing tmpl/include/layout.tx
    [Flavor::Basic] writing tmpl/include/pager.tx
    [Flavor::Basic] writing lib/BBS.pm
    [Flavor::Basic] writing lib/BBS/Web.pm
    [Flavor::Basic] writing lib/BBS/Web/Plugin/Session.pm
    [Flavor::Basic] writing lib/BBS/Web/Dispatcher.pm
    [Flavor::Basic] writing lib/BBS/Web/View.pm
    [Flavor::Basic] writing lib/BBS/Web/ViewFunctions.pm
    [Flavor::Basic] writing lib/BBS/DB.pm
    [Flavor::Basic] writing lib/BBS/DB/Schema.pm
    [Flavor::Basic] writing lib/BBS/DB/Row.pm
    [Flavor::Basic] writing script/bbs-server
    [Flavor::Basic] writing Build.PL
    [Flavor::Basic] writing minil.toml
    [Flavor::Basic] writing builder/MyBuilder.pm
    [Flavor::Basic] writing cpanfile
    [Flavor::Basic] writing static//js/jquery-2.0.3.min.js
    [Flavor::Basic] writing static//bootstrap/fonts/glyphicons-halflings-regular.eot
    [Flavor::Basic] writing static//bootstrap/css/bootstrap-theme.min.css
    [Flavor::Basic] writing static//bootstrap/fonts/glyphicons-halflings-regular.woff
    [Flavor::Basic] writing static//bootstrap/fonts/glyphicons-halflings-regular.ttf
    [Flavor::Basic] writing static//bootstrap/css/bootstrap.min.css
    [Flavor::Basic] writing static//bootstrap/js/bootstrap.min.js
    [Flavor::Basic] writing static//bootstrap/fonts/glyphicons-halflings-regular.svg
    [Flavor::Basic] writing static//bootstrap/js/bootstrap.js
    [Flavor::Basic] writing static//bootstrap/css/bootstrap.css
    [Flavor::Basic] writing static//bootstrap/css/bootstrap-theme.css
    [Flavor::Basic] writing static//js/es5-shim.min.js
    [Flavor::Basic] writing static//js/micro_template.js
    [Flavor::Basic] writing static//js/strftime.js
    [Flavor::Basic] writing static//js/sprintf-0.7-beta1.js
    [Flavor::Basic] writing static//js/micro-location.js
    [Flavor::Basic] writing static//js/micro_dispatcher.js
    [Flavor::Basic] writing static//js/xsrf-token.js
    [Flavor::Basic] writing static/img/.gitignore
    [Flavor::Basic] writing static/robots.txt
    [Flavor::Basic] writing static/js/main.js
    [Flavor::Basic] writing static/css/main.css
    [Flavor::Basic] writing db/.gitignore
    [Flavor::Basic] writing config/development.pl
    [Flavor::Basic] writing config/production.pl
    [Flavor::Basic] writing config/test.pl
    [Flavor::Basic] writing sql/mysql.sql
    [Flavor::Basic] writing sql/sqlite.sql
    [Flavor::Basic] writing t/Util.pm
    [Flavor::Basic] writing t/00_compile.t
    [Flavor::Basic] writing t/01_root.t
    [Flavor::Basic] writing t/02_mech.t
    [Flavor::Basic] writing t/03_assets.t
    [Flavor::Basic] writing t/06_jshint.t
    [Flavor::Basic] writing xt/01_pod.t
    [Flavor::Basic] writing xt/02_perlcritic.t
    [Flavor::Basic] writing .gitignore
    [Flavor::Basic] writing .proverc
    [Flavor::Basic] writing static/500.html
    [Flavor::Basic] writing static/504.html
    [Flavor::Basic] writing static/503.html
    [Flavor::Basic] writing static/502.html
    [Flavor::Basic] writing static/404.html
    There is no git command.


    Setup script was done! You are ready to run the skelton.
    
    You need to install the dependencies by:
    
        > carton install
    
    And then, run your application server:
    
        > carton exec perl -Ilib script/bbs-server
    
    --------------------------------------------------------------
    


    Вроде все ок, но не хватает carton и рекомендуется ввести еще несколько команд.
    Ставим его
    cpan Carton  # От рута
    carton install #  Надо делать в папке BBS! Не от рута!
    

    Получаем следующую структуру файлов и директорий:

    builder  Build.PL  config  cpanfile  cpanfile.snapshot  db  lib  local  minil.toml  script  sql  static  t  tmpl  xt
    


    Создание веб приложения



    cd db
    vim sqlite.sql
    


    Файл sqlite.sql со следующим содержанием:

    CREATE TABLE IF NOT EXISTS member (
        id           INTEGER NOT NULL PRIMARY KEY,
        name         VARCHAR(255)
    );
    
    CREATE TABLE IF NOT EXISTS sessions (
        id           CHAR(72) PRIMARY KEY,
        session_data TEXT
    );
    
    CREATE TABLE IF NOT EXISTS entry (
        entry_id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
        body varchar(255) not null
    );
    
    


    Создаем базу:

    sqlite3 development.db < sqlite.sql  
    


    Далее

    cd config/
    vim  development.pl
    


    Втыкаем в него вот такой конфиг:

    use File::Spec;
    use File::Basename qw(dirname);
    my $basedir = File::Spec->rel2abs(File::Spec->catdir(dirname(__FILE__), '..'));
    my $dbpath = File::Spec->catfile($basedir, 'db', 'development.db');
    +{
        'DBI' => [
            "dbi:SQLite:dbname=$dbpath", '', '',
            +{
                sqlite_unicode => 1,
            }
        ],
    };
    


    Пытаемся для теста запустить веб сервер.

     perl -Ilib script/bbs-server
    Can't locate Teng/Schema/Declare.pm in @INC (you may need to install the Teng::Schema::Declare module) (@INC contains: script/../lib lib /etc/perl /usr/local/lib/perl/5.18.1 /usr/local/share/perl/5.18.1 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5.18 /usr/share/perl/5.18 /usr/local/lib/site_perl .) at script/../lib/BBS/DB/Schema.pm line 6.
    BEGIN failed--compilation aborted at script/../lib/BBS/DB/Schema.pm line 6.
    Compilation failed in require at script/../lib/BBS.pm line 7.
    BEGIN failed--compilation aborted at script/../lib/BBS.pm line 7.
    Compilation failed in require at /usr/share/perl/5.18/parent.pm line 20.
    BEGIN failed--compilation aborted at script/../lib/BBS/Web.pm line 5.
    Compilation failed in require at script/bbs-server line 9.
    BEGIN failed--compilation aborted at script/bbs-server line 9.
    


    И обламываемся.
    Хорошо, ставим
    cpan Teng::Schema::Declare
    cpan Module::Functions
    cpan Plack::Middleware::ReverseProxy
    cpan Plack::Handler::Starlet
    


    Наконец-то увидели заветное:

    dotcloud@debian:~/BBS$ perl -Ilib script/bbs-server
    BBS: http://127.0.0.1:5000/
    


    Если зайти по этому адресу, то можно увидеть вот такую неземную красотищу:



    Теперь осталось из этого хозяйства сделать ВВS — доску объявлений (бабку бибисиху — знаете такую?)

    vim lib/BBS/DB/Schema.pm
    

    И постим туда следующее:

    
    package BBS::DB::Schema;
    use strict;
    use warnings;
    use utf8;
    
    use Teng::Schema::Declare;
    
    base_row_class 'BBS::DB::Row';
    
    table {
        name 'sessions';
        pk 'id';
        columns qw(session_data);
    };
    
    table {
        name 'entry';
        pk 'entry_id';
        columns qw(entry_id body);
    };
    
    1;
    


    Далее:

    vim lib/BBS/Web/Dispatcher.pm
    


    package BBS::Web::Dispatcher;
    use strict;
    use warnings;
    
    use Amon2::Web::Dispatcher::Lite;
    
    any '/' => sub {
        my ($c) = @_;
    
        my @entries = $c->db->search(
            entry => {
            }, {
                order_by => 'entry_id DESC',
                limit    => 10,
            }
        );
        return $c->render( "index.tx" => { entries => \@entries, } );
    };  
    
    post '/post' => sub {
        my ($c) = @_;
    
        if (my $body = $c->req->param('body')) {
            $c->db->insert(
                entry => +{
                    body => $body,
                }
            );
        }
        return $c->redirect('/');
    };
    
    1;
    


    И правим темплейт

    vim tmpl/index.tx
    


    : cascade "include/layout.tx"
    
    : override content -> {
    
    <form method="post" action="<: uri_for('/post') :>">
        <input type="text" name="body" />
        <input type="submit" value="Send" />
    </form>
    
    <ul>
        <: for $entries -> $entry { :>
        <li><: $entry.entry_id :>. <: $entry.body :></li>
        <: } :>
    </ul>
    
    : }
    


    Запускаем:

    perl -Ilib script/bbs-server
    


    И при необходимости доустанавливаем следующие пакеты

    cpan Router::Simple
    cpan Router::Simple::Sinatraish 
    cpan DBD::SQLite
    


    УРА!
    Бабка бибисиха — работает!



    Осталось все это задеплоить на nginx

    Устанавливаем nginx в качестве фронтэнда



    Сначала делаем init файл, и чтобы запускался не от рута


    vim /etc/init.d/plackup 
    


    #!/bin/sh
    
    PORT=5000
    WORKERS=4
    AMON_DIR="/home/dotcloud/BBS"
    AMON_APP="$AMON_DIR/script/bbs-server"
    AMON_USER="dotcloud"
    AMON_MODE="development"
    website="cc_Website"
    plackup="/usr/local/bin/plackup "
    PID=$AMON_DIR/logs/plackup.$website.pid
    plackup_args="-E $AMON_MODE -p $PORT -s Starman --pid=$PID --workers $WORKERS -D"
    
    U=`id -un`
    if [ $U = root ]; then
           WRPERM=`find $AMON_DIR/ ! -user $AMON_USER | wc -l`
           if [ "$WRPERM" != 0 ]; then
                   echo Fixing file ownership on $AMON_DIR
                   chown -R $AMON_USER.nginx $AMON_DIR
           fi
           cd /
           su $AMON_USER -s /bin/sh  $0 "$@"
           exit
    elif [ $U != $AMON_USER ]; then
           echo "Should be run under $AMON_USER or root"
           exit 1
    fi
    
    
    lockfile=$AMON_DIR/logs/plackup.$website
    
    start() {
        [ -x $plackup ] || exit 5
        [ -f $AMON_APP ] || exit 6
        echo -n $"Starting $website: "
        $plackup $plackup_args -a $AMON_APP 2>&1 > /dev/null
        retval=$?
        if [ $retval -eq 0 ]; then
            echo OK
            touch $lockfile
        else
            failure $"Unable to start"
        fi
        echo
        return $retval
    }
    
    stop() {
        echo -n $"Stopping $website: OK"
        if [ -f $PID ]; then
            kill `cat $PID` > /dev/null
            retval=$?
            [ $retval -eq 0 ] && rm -f $lockfile
            echo
            return $retval
        fi
        failure $"pid $PID not found"
        echo
        return 1
    }
    
    restart() {
        stop
        start
    }
    
    case "$1" in
        start)
            $1
            ;;
        stop)
            $1
            ;;
        restart)
            $1
            ;;
        *)
            echo $"Usage: $0 {start|stop|restart}"
            exit 2
    esac
    


    Добавляем конфиг в nginx

    vim /etc/nginx/conf.d/virtual.conf
    


    upstream amon {
            server 127.0.0.1:5000;
    }
    
    server {
        listen          *:80; 
        
        location / {
                    try_files /empty  @backend;
        }
    
      
        location @backend {
                proxy_set_header Host $http_host;
                proxy_set_header X-Forwarded-Host $host;
                proxy_set_header X-Real-IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header X-Forwarded-Proto $scheme;
                proxy_pass http://amon;
        }
    
    
    }
    


    Все готово!

    Заключение



    В качестве заключения я приведу опять-таки цитату из того самого интервью, с которого все началось:
    Расскажи об Amon2. Чем он отличается от других Perl-фреймворков для веб?
    Amon2 очень простой, надежный веб-фреймворк общего назначения.

    Отличия от Mojolicious

    Mojolicious неплох, и мне нравится сам подход. К сожалению, там не сохраняется обратная совместимость. В Amon2 же наоборот. Мне кажется, что ломать обратную совместимость можно только с изменением названия. Когда я решу что-либо серьезно изменить, я выпущу Amon3.

    Отличия от Catalyst

    Catalyst зависит от Moose, а Amon2 — нет. Это потому, что я хочу, чтобы мои приложения загружались быстро.

    Отличия от Dancer

    Практически нет никаких отличий между Amon2 и Dancer, включая Dancer2.



    Автор скромняга, конечно.

    А теперь мое имхо:
    1. Фреймворк и правда очень легковесный
    2. Написан японцем, с их тщательностью и перфекционизмом. Это ощущается в коде.
    3. Miyagawa, который написал plackup, с ним корешится, что называется, два сапога пара.
      Ведь используется и рекомендуется именно такая связка plackup + Amon2
    4. Надеюсь, что фрейворк, который юзают «более миллиона человек» по заявлению автора, не будет брошен просто так, а будет развиваться дальше.
    5. Фрейворк — относительно новый и современный, но уже есть громадное кол-во модулей на cpan
    6. В целом оставил приятное впечатление.
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 21

      +20
      ждал очередное творение на node а тут бах! перловый фреймворк, неожиданно, приятно, интересно, но…
        +1
        Вот с таким же непонятным каким-то чувством «но», я тоже завис. Нахлынули старые воспоминания. Вобщем, надо будет повтыкать… Топикстартеру — спасибо!
        0
        > Надеюсь, что фрейворк, который юзают «более миллиона человек» по заявлению автора
        «Юзает» тут подразумевает, что некие разработчики используют указанный фреймворк в своей разработческой деятельности?

        > Некоторыми приложениями нашей компании пользуются более миллиона человек. Все это работает на Amon2
        Если я правильно понял, то тут написано, что продуктами пользуется большое число человек. А продукты написаны на Amon2.
        А сколько разработчиков, которые им пользуются, из этой реплики не ясно.
          +4
          Это вы лучше у Tokuhiro Matsuno спросите :)



          Как еще можно трактовать эту цитату:
          Я пишу серверную часть на Perl. Некоторыми приложениями нашей компании пользуются более миллиона человек. Все это работает на Amon2.


          Почему-то, вспоминается фильм «Lost in Translation»

            –1
            Я спрашивал у вас про ваше слово «юзают».
              0
              Эту цитату можно трактовать как «у приложения, которое написано на Amon2, более миллиона пользователей». И в этом случае забросить фреймворк ничего не стоит — достаточно просто переехать на новый, сложность чего зависит только от сложности приложения.
                0
                Я и не спорю.
                Все может умереть, любой проект. И амон2 в том числе.

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

                И не подумайте, что я тут защищаю или как-то продвигаю его.
                Просто делюсь своими мыслями.
                  0
                  Вот как раз у продукта, используемого (одной?) крупной корпорацией шансы на «переезд» выше — сменился менеджмент, сменился продукт.
                    0
                    Рассмотрим другой случай — делал фреймоворк энтузиаст.
                    Просто ради прикола.
                    Энтузиазм — пропал.
                    Фреймворк — умер.

                    Здесь человек работает в крупной компании. И свой же собственный продукт сразу же и внедряет. Не забываем про трудоголизм японцев.
                    Я не знаю, что лучше или хуже. Я не психолог и не маркетолог.

                      0
                      А одинаково. Человек работает в крупной компании, а потом больше не работает. По произвольной причине. Судьба фреймворка непредсказуема.
                        –1
                        Может я ошибаюсь. Но мне кажется, что не одинаково.
                        Одно дело теории, а другое дело вот он реальный продакшен с миллионами юзеров.

            0
            Tatsuhiko Miyagawa — девушка? Seriously?
              0
              Сорри, попутал. Думал о своем, о девичьем :)
              • UFO just landed and posted this here
              +1
              В интервью японца Tokuhiro Matsuno <...>


              Корректнее:

              В интервью японца Мацуно Токухиро (徳廣松野) <...>
                0
                Да, верно, как вы сказали. На cpan он себя именно так и называет MATSUNO★Tokuhiro.

                Я не знаю, почему в интервью Tokuhiro Matsuno.
                  +1
                  Потому что интервью переведено с английского языка людьми, которые не умеют или не хотят правильно русифицировать японские собственные, и оставляют латиницу. По-русски принято писать имя-фамилия, даже если в родном языке носителя имени порядок фамилия-имя.
                0
                Японцы в плане интернета как обычно «впереди планеты всей»… :(
                  +1
                  Спасибо за статью.

                  Использовал этот фреймворк, нужно было сделать небольшое отдельное приложение по выводу статистики, хотел сначала Dancer, т.к. неплохо им владею, но захотелось что-нибудь поверх PSGI/Plack, в целом оставил приятное впечатление, ну и Plack радует конечно =))

                  Еще советую обратить внимание вот на этот минималистичный фреймворк: Kelp, так же поверх PSGI/Plack и с минимальным кол-ом кода.
                    0
                    Это вам спасибо за Kelp!

                    Попробовал
                    # cpanm Kelp 
                    --> Working on Kelp
                    Fetching http://www.cpan.org/authors/id/M/MI/MINIMAL/Kelp-0.457.tar.gz ... OK
                    Configuring Kelp-0.457 ... OK
                    Building and testing Kelp-0.457 ... OK
                    Successfully installed Kelp-0.457
                    1 distribution installed
                    # 
                    # 
                    # adduser Kelp
                    # su - Kelp
                    $ 
                    $ 
                    $ Kelp MyApp
                    Creating folder: ./log
                    Writing file: ./log/keep
                    Creating folder: ./lib
                    Writing file: ./lib//MyApp.pm
                    Creating folder: ./conf
                    Writing file: ./conf/deployment.pl
                    Writing file: ./app.psgi
                    Writing file: ./conf/test.pl
                    Creating folder: ./t
                    Writing file: ./t/main.t
                    Writing file: ./conf/config.pl
                    Writing file: ./conf/development.pl
                    Creating folder: ./views
                    Writing file: ./views/home.tt
                    $ 
                    $ 
                    $ 
                    
                    $ /usr/local/bin/plackup  -Ilib -E deployment -s Twiggy -a app.psgi -p 5000
                    
                    
                    # curl   http://127.0.0.1:5000/home  
                    Hello, world!
                    # curl   http://127.0.0.1:5000/config
                    {"modules":["Template","JSON","Logger"],"app_url":"http://localhost:5000","modules_init":{"JSON":{"allow_blessed":1,"pretty":0,"convert_blessed":1,"utf8":1},"Template":{"encoding":"utf8","paths":["/home/Kelp/views","/home/Kelp/../views"]},"Routes":{"base":"MyApp"},"Logger":{"outputs":[["File","name","error","filename","log/error.log","min_level","error","mode",">>","newline",1,"binmode",":encoding(UTF-8)"]]}},"middleware":[],"charset":"UTF-8","middleware_init":{}}
                    




                    Буду использовать.

                      0
                      так быстро =)
                      удачи вам

                      у меня вот щас есть небольшая задачка, для себя, вот разрываюсь между амоном и келпом =)

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