c641be1c4e23722ddd81992f6379848def48ca04
[scpubgit/Clifton.git] / lib / App / Clifton / Task.pm
1 package App::Clifton::Task;
2
3 use Log::Contextual qw(:log);
4 use Async::MergePoint;
5 use Moo;
6
7 extends 'App::Clifton::Component';
8
9 has on_finished => (is => 'rw');
10
11 has name => (is => 'ro', required => 1);
12
13 has body => (is => 'ro', required => 1);
14
15 has guard => (is => 'ro', predicate => 'has_guard');
16
17 has args => (is => 'ro', required => 1);
18
19 has dependencies => (is => 'ro', default => sub { {} });
20
21 has merge_point => (is => 'lazy');
22
23 sub _build_merge_point { Async::MergePoint->new }
24
25 sub BUILD {
26   my ($self) = @_;
27   if (my $cb = $self->args->{on_finished}) {
28     $self->on_finished($cb);
29   }
30   my $deps = $self->dependencies;
31   if (my @needs = keys %$deps) {
32     my $mp = $self->merge_point;
33     $mp->needs(@needs);
34     foreach my $key (@needs) {
35       $deps->{$key}->on_finished(sub { $mp->done($key => $_[0]) });
36     }
37     $mp->close(on_finished => $self->_capture_weakself('_schedule_body'));
38   } else {
39     $self->_schedule_body;
40   }
41 }
42
43 sub _schedule_body {
44   my ($self, %args) = @_;
45   my $fire_body = $self->_capture_weakself('_fire_body');
46   $args{on_finished} = $self->_finished_callback;
47   %args = (%{$self->args}, %args);
48   $self->_schedule(sub { $fire_body->(\%args); });
49 }
50
51 sub _fire_body {
52   my $self = shift;
53   if ($self->has_guard and my ($result) = $self->guard->(@_)) {
54     $_[0]->{on_finished}($result);
55   } else {
56     $self->body->(@_);
57   }
58 }
59
60 sub _finished_callback {
61   my ($self) = @_;
62   $self->_capture_weakself('_schedule_finished');
63 }
64
65 sub _schedule_finished {
66   my ($self, @args) = @_;
67   if (my $on_finished = $self->on_finished) {
68     $self->_schedule(sub { $on_finished->(@args) });
69   }
70   $self->parent->remove_child($self);
71 #$self->$::Dwarn;
72 #warn Devel::FindRef::track $self;
73 }
74
75 1;