Search code examples
perlasteriskasteriskami

Perl order of execution of asterisk callback?


I have a code as follow:

 1  sub do_leave {
 2
 3    my ($asterisk, $event) = @_;
 4    my $join_id;
 5    my $id = $astman->send_action({ Action    => 'Getvar',
 6                                    Variable  => 'join_id',
 7                                    Channel   => $event->{'Channel'},
 8                                  }, \&get_value, undef, \$join_id);
 9
10    sleep(2);
11    say "join_id is: $join_id";
12
13    my $sql = "UPDATE conference_log SET duration=(TIMESTAMPDIFF(SECOND, (SELECT start_conf), NOW())), end_conf=(NOW()) WHERE id=?";
14    my $sth = $dbh->prepare($sql);
15    $sth->execute($join_id);
16  }
17
18  sub get_value {
19    my ($ast, $resp, $ref_join_id) = @_;
20    for my $key (keys %$resp) {
21      if ($key eq "PARSED") {
22        $$ref_join_id = $resp->{$key}{"Value"};
23      }
24    }
25  }

I'm using Asterisk::AMI module for getting information from asterisk AMI. the do_leave sub is called whenever someone leaves the conference. My question is get_value callback executed after all statements in do_leave. How can i make get_value callback executed before line 10. Variable \$join_id in send_action is third argument to the callback. I need $join_id variable before sql statements.


Solution

  • I've not worked with Asterisk::AMI, but I assume that the reason the send_action method takes a callback method is that the result comes back asynchronously. You can't guarantee how long that will take.

    A quick and easy solution is to place the database update inside the callback function like this:

    sub do_leave {
    
      my ($asterisk, $event) = @_;
      my $get_value = sub {
        my ($ast, $resp, $ref_join_id) = @_;
        for my $key (keys %$resp) {
            if ($key eq "PARSED") {
                my $ref_join_id = $resp->{$key}{"Value"};
                my $sql = "UPDATE conference_log SET duration=(TIMESTAMPDIFF(SECOND, (SELECT start_conf), NOW())), end_conf=(NOW()) WHERE id=?";
                my $sth = $dbh->prepare($sql);
                $sth->execute($join_id);
            }
        }
      };
    
      my $id = $astman->send_action({ Action    => 'Getvar',
                                      Variable  => 'join_id',
                                      Channel   => $event->{'Channel'},
                                    }, $get_value);
    
    }
    

    Notice that I have used an anonymous sub, assigned to a variable, which would allow you to share variables between the outer do_leave sub and the callback sub (this is called a closure). However in this case it is probably not needed since there are no shared variables.