0741abb89947720bfc0146ac6d97dd9a9d5c97cb
[cloudstore.git] / rsync-piper.pl
1 #!/usr/bin/perl
2 use warnings;
3 use strict;
4
5 use autodie;
6 use POSIX;
7 use File::Slurp;
8 use IO::Select;
9 use Time::HiRes;
10 use Data::Dump qw(dump);
11 use English;
12 use JSON::XS;
13
14 my $dir   = $ENV{RSYNC_DIR}  || '/srv/cloudstore/var';
15 my $port  = $ENV{RSYNC_PORT} || 6501;
16 my $users = "users";
17
18 my $log_fifo = "$dir/$port.log";
19 my $pid_file = "$dir/$port.pid";
20 my $cfg_file = "$dir/$port.conf";
21
22 my @transfer = qw(
23 timestamp:%t:timestamp
24 login:%u:text
25 port:$port:int
26 pid:%p:int
27 perms:%B:text
28 itemize:%i:text
29 mtime:%M:timestamp
30 op:%o:text
31 size:%l:int
32 transfered:%b:int
33 file:%f:text
34 );
35
36 $transfer[2] = "port:$port:int"; # expand $port
37
38 my @transfer_names =          map { ( split(/:/,$_,3) )[0] } @transfer;
39 my $transfer_log   = join(' ',map { ( split(/:/,$_,3) )[1] } @transfer );
40
41 if ( $ENV{SQL} ) {
42         print "CREATE TABLE rsync_transfer (\n\t",
43         join(",\n\t", map { my @m = split(/:/,$_,3); "$m[0] $m[2]" } @transfer),
44         "\n);\n";
45         exit 1;
46 }
47
48 mkdir $dir if ! -e $dir;
49
50 mkfifo $log_fifo, 0700 unless -p $log_fifo;
51
52 my $rsync_config = qq{
53
54 #uid = nobody
55 #gid = nogroup
56 #use chroot = yes
57 use chroot = no
58
59 #max connections = 4
60 lock file = $dir/rsyncd.lock
61
62 #syslog facility = local5
63 log file  = $log_fifo
64
65 transfer logging = yes
66 log format = transfer-log:$transfer_log
67 max verbosity = 5
68
69 pid file  = $pid_file
70
71 # don't check secrets file permission (uid)
72 strict modes = no
73
74 pre-xfer exec = /srv/cloudstore/pre-xfer.sh
75 post-xfer exec = /srv/cloudstore/post-xfer.sh
76
77 [dpavlin]
78         path = /srv/cloudstore/users/dpavlin/blob
79         auth users = dpavlin
80         secrets file = /srv/cloudstore/secrets/dpavlin
81         read only = false
82
83 };
84
85 write_file $cfg_file, $rsync_config;
86 warn "created $cfg_file ", -s $cfg_file, " bytes\n";
87
88 if ( -e $pid_file ) {
89         my $pid = read_file $pid_file;
90         chomp($pid);
91         if ( kill 0, $pid ) {
92                 warn "found rsync pid $pid";
93         } else {
94                 unlink $pid_file;
95         }
96 }
97
98 if ( ! -e $pid_file ) {
99         my $exec = "rsync --daemon --config $cfg_file --no-detach --port=$port";
100         warn "START $exec\n";
101
102         die "could not fork\n" unless defined(my $pid = fork);
103         unless ($pid) {
104                 warn "start server with $exec\n";
105                 exec $exec || die $!;
106         }
107
108         warn "wait for pid file";
109         while ( ! -e $pid_file ) {
110                 sleep 1;
111         }
112 }
113
114 use Gearman::Client;
115 my $gearman = Gearman::Client->new;
116 $gearman->job_servers('127.0.0.1:4730');
117
118 while(1) {
119         warn "# reading log output from $log_fifo\n";
120         open(my $fifo, '<', $log_fifo);
121         while( my $line = <$fifo> ) {
122                 chomp $line;
123                 print $line, $/;
124                 if ( $line =~ /transfer-log:(.+)/ ) {
125                         my $transfer = $1;
126                         $transfer =~ s|(\d\d\d\d)/(\d\d)/(\d\d)[-\s](\d\d:\d\d:\d\d)|$1-$2-$3T$4|g;
127 warn "XXX $transfer";
128                         my ( $yyyy,$mm,$dd,undef,$login,undef ) = split( /[\-T\s]/, $transfer, 6 );
129
130                         my $path = "users/$login/log";
131                         mkdir $path unless -d $path;
132                         $path .= "/$yyyy-$mm-$dd";
133 warn "## $path $transfer\n";
134                         my $new_log = ! -e $path;
135                         open( my $log, '>>', $path );
136                         print $log join(' ',@transfer),"\n" if $new_log; # store header
137                         print $log "$transfer\n";
138                         close $log;
139
140
141                         my @v = split(/\s+/,$transfer,$#transfer + 1);
142                         my %data;
143                         @data{@transfer_names} = @v ; # FIXME validate?
144
145                         print ">>> data ",dump( \%data );
146
147                         $gearman->dispatch_background( 'rsync_transfer' => encode_json \%data );
148
149                 }
150         }
151         close($fifo);
152         sleep 1;
153 }
154