File Coverage

blib/lib/DynGig/Range/Cluster/Client.pm
Criterion Covered Total %
statement 18 64 28.1
branch 0 38 0.0
condition 0 9 0.0
subroutine 6 11 54.5
pod 2 3 66.6
total 26 125 20.8


line stmt bran cond sub pod time code
1             =head1 NAME
2              
3             DynGig::Range::Cluster::Client - Cluster client
4              
5             =cut
6             package DynGig::Range::Cluster::Client;
7              
8 1     1   5 use warnings;
  1         2  
  1         28  
9 1     1   5 use strict;
  1         14  
  1         28  
10 1     1   5 use Carp;
  1         2  
  1         60  
11              
12 1     1   885 use DynGig::Util::Sysrw;
  1         3133  
  1         27  
13 1     1   1098 use DynGig::Multiplex::TCP;
  1         26873  
  1         36  
14 1     1   1121 use DynGig::Range::Cluster::Config;
  1         4  
  1         905  
15              
16             =head1 SYNOPSIS
17              
18             ## a network client
19             my $client1 = DynGig::Range::Cluster::Client->new
20             (
21             server => 'localhost:12345',
22             timeout => 10
23             );
24              
25             ## a Unix domain socket client
26             my $client2 = DynGig::Range::Cluster::Client->new
27             (
28             server => '/unix/domain/socket'
29             timeout => 20
30             );
31              
32             ...
33              
34             ## write cache
35             $client1->cache( cache => '/cache/dir' );
36              
37             ## refresh data
38             $client2->update();
39            
40             ## get the value of node 'foo' for cluster 'c1'
41             my $value = $client2->node( cluster => 'c1', key => 'foo' );
42              
43             ## get the nodes for cluster 'c1' where the value is 'DOWN'
44             my $keys = $client2->node( cluster => 'c1', value => 'DOWN' );
45              
46             ## get all cluster names where the attr key is 'foo' and value is 'bar'
47             my $clusters = $client2->attr( key => 'foo', value => 'bar' );
48              
49             =cut
50             sub new
51             {
52 0     0 0   my ( $class, %param ) = @_;
53 0           my $server = $param{server};
54              
55 0 0         croak "server not defined" unless defined $server;
56              
57 0           $param{buffer} = '00000000000000000000000000000000';
58 0           delete $param{server};
59              
60 0   0       my $this = bless +{ server => $server, param => \%param },
61             ref $class || $class;
62              
63 0 0         croak "unable to get config from server/cache" unless $this->update();
64 0           return $this;
65             }
66              
67             =head1 METHODS
68              
69             =head2 update()
70              
71             Returns I if successful, I otherwise.
72              
73             =cut
74             sub update
75             {
76 0     0 1   my $this = shift;
77 0           my $param = $this->{param};
78 0           my $client = DynGig::Multiplex::TCP->new( $this->{server} => $param );
79              
80 0 0         return 0 unless $client->run( index => 'forward' );
81 0 0         return 0 unless my $result = $client->result();
82 0 0         return 0 unless $result = ( values %$result )[0];
83 0 0         return 0 unless
84             my $config = DynGig::Range::Cluster::Config::unzip( $result );
85              
86 0           $this->{config} = $config;
87 0           $this->{md5} = $param->{buffer} = $config->md5();
88 0           $this->{zip} = $result;
89              
90 0           return 1;
91             }
92              
93             =head2 cache( cache => dir )
94              
95             Writes config to the cache directory.
96             Sets current symlink to the latest cache file. Returns the object.
97              
98             =cut
99             sub cache
100             {
101 0     0 1   my ( $this, %param ) = @_;
102 0           my $cache = $param{cache};
103              
104 0 0         if ( ! defined $cache )
    0          
105             {
106 0           $this->{cache} = '.';
107             }
108             elsif ( ! defined $this->{cache} )
109             {
110 0           my $path = eval { readlink $cache };
  0            
111 0 0         $path = $cache unless defined $path;
112              
113 0 0         if ( -d $path )
114             {
115 0 0 0       croak "inaccessible directory $cache" unless -w $path && -x $path;
116             }
117             else
118             {
119 0 0         croak "invalid cache $cache" if -e $path;
120 0 0         croak "mkdir $cache: $!" unless mkdir $path;
121             }
122              
123 0           chdir( $this->{cache} = $cache );
124             }
125              
126 0           my $md5 = $this->{md5};
127              
128 0 0         unless ( -f $md5 )
129             {
130 0 0         croak "open $md5: $!" unless open my $handle, '+>', $md5;
131              
132 0           DynGig::Util::Sysrw->write( $handle, $this->{zip} );
133 0           close $handle;
134             }
135              
136 0 0         my $link = defined $param{link} ? $param{link} : 'current';
137              
138 0 0 0       croak "unlink $link: $!" if -l $link && ! unlink $link;
139 0 0         croak "symlink $md5 $link: $!" unless symlink $md5, $link;
140              
141 0           return $this;
142             }
143              
144             =head2 Autoloaded Methods $attribute( %query )
145              
146             See DynGig::Range::Cluster::Config
147              
148             =cut
149             sub AUTOLOAD
150             {
151 0     0     my $this = shift;
152 0           my $config = $this->{config};
153              
154 0 0         return our $AUTOLOAD =~ /::(\w+)$/ ? $config->$1( @_ ) : undef;
155             }
156              
157             sub DESTROY
158             {
159 0     0     my $this = shift;
160 0           map { delete $this->{$_} } keys %$this;
  0            
161             }
162              
163             =head1 NOTE
164              
165             See DynGig::Range::Cluster
166              
167             =cut
168              
169             1;
170              
171             __END__