Group
Extension

Salvation-MongoMgr/lib/Salvation/MongoMgr/Connection.pm

package Salvation::MongoMgr::Connection;

use utf8;
use strict;
use warnings;
use boolean;
use feature 'state';

use URI ();
use JSON 'from_json';
use File::Slurp 'read_file';
use Salvation::TC ();
use MongoDB ();


sub new {

    my ( $proto, %args ) = @_;

    Salvation::TC -> assert( \%args, 'HashRef(
        Str :db!
        Str :config_file!,
        Maybe[Str] :auth_config_file,
        Int :timeout,
        Int :query_timeout,
        Int :wtimeout,
        Str :auth_db_name,
        Str :host,
        Str :use_auth_for,
        Bool :find_master
    )' );

    $args{ 'auth_db_name' } //= 'admin';

    unless( exists $args{ 'find_master' } ) {

        $args{ 'find_master' } = true;
    }

    unless( exists $args{ 'use_auth_for' } ) {

        $args{ 'use_auth_for' } = $args{ 'db' };
    }

    my $self = bless( \%args, ( ref( $proto ) || $proto ) );

    if( defined( my $auth_config_file = $self -> auth_config_file() ) ) {

        my $rv = from_json( scalar( read_file( $auth_config_file ) ) );

        Salvation::TC -> assert( $rv, sprintf( 'HashRef(
            HashRef(
                HashRef(
                    Str :login!,
                    Str :password!
                ) :%s!
            ) :db_auth!

        )', $self -> { 'use_auth_for' } ) );

        $self -> { '_auth_info' } = $rv;

    } else {

        $self -> { '_auth_info' } = { db_auth => { $self -> { 'use_auth_for' } => {} } };
    }

    $self -> { '_mongo_servers_list' } = join( ',', @{ $self -> servers_list() } );

    return $self;
}

sub make_connection_string {
    my ($self, $mongo_servers_list) = @_;
    $mongo_servers_list //= $self -> { '_mongo_servers_list' };
    return "mongodb://${mongo_servers_list}" . ($self->{connection_args} // '');
}

sub _connect {

    my ( $self ) = @_;
    my $mongo_servers_list = $self -> { '_mongo_servers_list' };
    my $dsn = join( "\0", $mongo_servers_list, $self -> { 'find_master' } );
    state $HMONGO = {};

    if(
        exists $HMONGO -> { $dsn }
        && ( $HMONGO -> { $dsn } -> { 'pid' } == $$ )
    ) {

        $self -> { '_connection' } = $HMONGO -> { $dsn } -> { 'handle' };

    } else {

        my ( $login, $password ) = @{ $self -> credentials() }{ 'login', 'password' };

        $self -> { '_connection' } = MongoDB::MongoClient -> new(
            host => $self->make_connection_string,
            timeout => ( $self -> { 'timeout' } // 20_000 ),
            query_timeout => ( $self -> { 'query_timeout' } // 600_000 ), # in ms
            wtimeout => ( $self -> { 'wtimeout' } // 30_000 ),
            find_master => $self -> { 'find_master' },
            auto_connect => 1,
            w => 1,
            dt_type => undef,
            db_name => $self -> { 'auth_db_name' },
            ( defined $login ? ( username  => $login ) : () ),
            ( defined $password ? ( password => $password ) : () ),
        );

        $HMONGO -> { $dsn } = {
            handle => $self -> { '_connection' },
            pid => $$,
        };
    }

    return $self -> { '_connection' };
}

sub credentials {

    my ( $self ) = @_;
    my ( $login, $password ) = @{ $self
        -> { '_auth_info' }
        -> { 'db_auth' }
        -> { $self -> { 'use_auth_for' } }
    }{ 'login', 'password' };

    return {
        login => $login,
        password => $password,
    };
}

sub config_file {

    my ( $self ) = @_;

    return $self -> { 'config_file' };
}

sub auth_config_file {

    my ( $self ) = @_;

    unless( exists $self -> { 'auth_config_file' } ) {

        $self -> { 'auth_config_file' } = $self -> { 'config_file' };
    }

    return $self -> { 'auth_config_file' };
}

sub servers_list {

    my ( $self ) = @_;

    unless( exists $self -> { 'servers_list' } ) {

        if( exists $self -> { 'host' } ) {

            $self -> { 'servers_list' } = [ $self -> { 'host' } ];

        } else {

            my $config = from_json( scalar( read_file( $self -> config_file() ) ) );

            Salvation::TC -> assert( $config, 'HashRef( ArrayRef[Str] :servers_list!, HashRef[Str] :connection_args )' );

            $self -> { 'servers_list' } = $config -> { 'servers_list' };

            if(exists($config->{connection_args})) {
                my $o = URI->new;
                $o->query_form(%{$config->{connection_args}});
                $self->{connection_args} = '/' . $o->as_string;
            }
        }
    }

    return $self -> { 'servers_list' };
}

sub get_connection {

    my ( $self ) = @_;

    return $self -> _connect();
}

sub get_database {

    my ( $self, $db ) = @_;

    return $self -> get_connection() -> get_database( $db // $self -> { 'db' } );
}

sub get_collection {

    my ( $self, $collection ) = @_;

    return $self -> get_database() -> get_collection( $collection );
}


1;

__END__


Powered by Groonga
Maintained by Kenichi Ishigaki <ishigaki@cpan.org>. If you find anything, submit it on GitHub.