Merge branch 'attr'
[cloudstore.git] / lib / CloudStore / API.pm
index 711833f..ef39524 100644 (file)
@@ -9,11 +9,13 @@ use base qw(CloudStore::Gearman CloudStore::MD5sum);
 use File::Path qw(make_path remove_tree);
 use File::Find;
 use Data::Dump qw(dump);
+use Carp qw(confess);
 
 sub new {
-       my ($class,$group) = @_;
+       my ($class,$slice) = @_;
 
-       my ( undef, $dir, $port, undef ) = getgrnam($group) || die "can't find group $group: $!";
+       my ( undef, $dir, $port, undef ) = getgrnam($slice);
+       die "can't find group $slice: $!" unless $dir && $port;
        my $self = {
                passwd => '/var/lib/extrausers/passwd',
                PORT => $port,
@@ -21,7 +23,17 @@ sub new {
        };
        bless $self, $class;
 
-       $self->{md5} = $self->user_info('md5');
+       $self->{md5} = $self->user_info("md5") || die "can't find user md5";
+       $self->{md5}->{dir} = "$dir/md5";
+       if ( ! -e $self->{md5}->{dir} ) {
+               make_path $self->{md5}->{dir}, { uid => $self->{md5}->{uid}, gid => $self->{md5}->{gid} };
+               warn "## CREATED md5pool $self->{md5}->{dir}\n";
+       }
+
+       my $name = $self->{SLICE};
+       $name =~ s/\W+/_/g;
+       $name =~ s/^_+//;
+       $self->{quota} = $name . '_quota';
 
        return $self;
 }
@@ -29,8 +41,11 @@ sub new {
 sub user_info {
        my ($self,$login) = @_;
 
+       confess "need login" unless $login;
+
        my @n = qw/ login passwd uid gid quota comment gecos dir shell expire /;
        my @p = $login =~ m/^\d+$/ ? getpwuid $login : getpwnam $login;
+       die "user_info $login: $@" if $@;
        my $user;
        $user->{$_} = shift @p foreach @n;
        return $user;
@@ -62,13 +77,15 @@ sub create_user {
                mkdir $dir;
                chown $max_uid, $self->{PORT}, $dir;
 
-               open($fh, '>', "$dir/.secrets");
+               my $path = "$dir/.meta/secrets";
+               $self->mkbasepath($path);
+               open($fh, '>', $path);
                print $fh "u$max_uid:$new_passwd\n";
                close $fh;
        }
 
        # FIXME update quota only on create?
-       $self->gearman_do( 'narada_s1_quota_set' => "$found $new_quota" );
+       $self->gearman_do( "$self->{quota}_set" => "$found $new_quota" );
 
        return $found;
 }
@@ -84,20 +101,37 @@ sub user_dir {
        $user = $self->user_info($user) unless ref $user eq 'HASH';
        my $path;
        if ( exists $user->{dir} ) {
-               $path = $user->{dir} . '/' . $dir;
+               $path = $user->{dir} . '/.meta/' . $dir;
        } else {
                die "no dir in ", dump $user;
        }
        $path =~ s{//+}{/}g;
-#      warn "## user_dir $path";
+
+       if ( ! -e $path ) {
+               $self->mkbasepath( $path, { uid => $user->{uid} } );
+               open(my $fh, '>', $path);
+               close $fh;
+               chown $user->{uid}, $user->{gid}, $path;
+               warn "# user_dir created $path\n";
+       }
+
+       #warn "### user_dir $path";
        return $path;
 }
 
 sub append {
        my $self = shift @_;
+       $self->append_meta( 'usage', @_ );
+}
+
+sub append_meta {
+       my $self = shift @_;
+       my $log  = shift @_;
        my $user = shift @_;
-       my $path = $self->user_dir( $user => '.log');
-       my $line = join('#',@_);
+       my $path = $self->user_dir( $user => $log );
+       my $delimiter = '#';
+          $delimiter = '  ' if $log =~ m/md5sum$/;
+       my $line = join($delimiter,@_);
        open(my $fh, '>>', $path);
        print $fh "$line\n";
        close $fh;
@@ -107,7 +141,7 @@ sub append {
 sub usage {
        my ( $self, $user ) = @_;
        $user = $self->user_info($user) unless ref $user eq 'HASH';
-       my $path = $self->user_dir( $user => '.log');
+       my $path = $self->user_dir( $user => 'usage');
        my $sum;
        open(my $fh, '<', $path);
        while(<$fh>) {
@@ -117,7 +151,7 @@ sub usage {
                $sum->{_usage}  += $v[1];
        }
        my ( $usage, $quota ) = split(/ /,
-               $self->gearman_do( 'narada_s1_quota_get' => $user->{uid} )
+               $self->gearman_do( "$self->{quota}_get" => $user->{uid} )
        );
        $sum->{_usage} += $usage;
        $sum->{_quota} = $quota;
@@ -129,6 +163,7 @@ sub send_file {
        my ( $self, $f_uid,$f_path, $t_uid,$t_path ) = @_;
 
        my $f = $self->user_info($f_uid);
+       die "FIXME not on current slice" if $f->{dir} !~ m/^$self->{SLICE}/;
        my $t = $self->user_info($t_uid);
 
        my $f_full = "$f->{dir}/$f_path";
@@ -148,15 +183,47 @@ sub send_file {
 
        $self->delete( $t, $t_path ) if -e $t_full;
 
-       link $f_full, $t_full; 
+       my $ok = link $f_full, $t_full; 
        $self->append( $t, 'recv', -s $t_full, $f->{uid}, $t_path );
+
+       $ok = -s $t_full if $ok; # replace true with file size
+
+       my $md5;
+       if ( $f->{uid} == $self->{md5}->{uid} ) {
+               $md5 = $f_path; # we don't have local md5sum db for md5 user!
+       } else {
+               $md5 = $self->md5_get($f_full);
+       }
+       if ( ! $md5 ) {
+               warn "ERROR: no md5 for $f_path";
+               return $ok;
+       }
+
+       $self->append_meta('md5sum', $t, $md5 => $t_path ); # md5sum for received files!
+
+       return $ok;
 }
 
 sub rename_file {
        my ( $self, $user, $from, $to ) = @_;
        $user = $self->user_info($user) unless ref $user eq 'HASH';
 
-       $self->append( $user, 'rename', $from, $to );
+       my $f_full = "$user->{dir}/$from";
+       my $t_full = "$user->{dir}/$to";
+
+       $self->mkbasepath( $t_full, { uid => $user->{uid}, gid => $user->{gid} } );
+       my $ok = rename $f_full, $t_full;
+
+       my $md5 = $self->md5_get($t_full);
+       if ( ! $md5 ) {
+               warn "ERROR: no md5sum for $from";
+               return $ok; # XXX our internal error
+       }
+
+       $self->append_meta('md5sum', $user, 'rename' => $from );
+       $self->append_meta('md5sum', $user, $md5 => $from );
+
+       return $ok;
 }
 
 
@@ -189,10 +256,17 @@ sub delete {
        warn "delete $deleted_size bytes shared\n";
 
        $self->append( $user, 'delete', -$deleted_size, $user->{uid}, $path );
+       $self->append_meta('md5sum', $user, 'delete', $path );
 
-       $self->md5sum($user)->out( $path );
-       
        return $full_path;
 }
 
+sub file_size {
+       my ( $self, $user, $path ) = @_;
+       $user = $self->user_info($user) unless ref $user eq 'HASH';
+
+       my $full_path = "$user->{dir}/$path";
+       return -s $full_path;
+}
+
 1;