App-Context

 view release on metacpan or  search on metacpan

lib/App/Context.pm  view on Meta::CPAN

            unshift(@$events, $event);
            if ($event->{time} && $event->{interval}) {
                $event->{time} += $event->{interval}; # reschedule the event
                $self->log({level=>5},"Event Rescheduled: time=$time [$event->{time}, every $event->{interval}] $event->{method}().\n");
                if ($time_of_next_event == 0 || $event->{time} < $time_of_next_event) {
                    $time_of_next_event = $event->{time};
                }
            }
            else {
                $self->log({level=>5},"Event Removed: time=$time [$event->{time}, every $event->{interval}] $event->{method}().\n");
                splice(@$scheduled_events, $i, 1); # remove the (one-time) event
                $event->{scheduled} = 0;
            }
        }
        else {
            if ($time_of_next_event == 0 || $event->{time} < $time_of_next_event) {
                $time_of_next_event = $event->{time};
            }
        }
    }
    &App::sub_exit($time_of_next_event) if ($App::trace);
    return($time_of_next_event);
}

# NOTE: send_event() is similar to call(). I ought to resolve this.
sub send_event {
    &App::sub_entry if ($App::trace);
    my ($self, $event) = @_;
    my $method = $event->{method};
    my @args = $event->{args} ? @{$event->{args}} : ();
    my $name = $event->{name};
    my $service_type = $event->{service_type};
    $service_type = "SessionObject" if (!$service_type && $name);
    my (@results);
    if ($name) {
        my $service = $self->service($service_type, $name);
        $self->log({level=>3},"Send Event: $service_type($name).$method(@args)\n");
        @results = $service->$method(@args);
    }
    else {
        $self->log({level=>3},"Send Event: $method(@args)\n");
        @results = $self->$method(@args);
    }
    &App::sub_exit(@results) if ($App::trace);
    if (wantarray()) {
        return(@results);
    }
    else {
        if ($#results == -1) {
            return(undef);
        }
        elsif ($#results == 0) {
            return($results[0]);
        }
        else {
            return(\@results);
        }
    }
}

# NOTE: The baseline context implements the API for asynchronous events
#       in a simplistic, sequential way.
#       It merely sends the event, then sends the callback event.
#       See App::Context::Server for a context that spawns processes which
#       execute the event.  When the process exits, the callback_event is fired.
#       See App::Context::Cluster for a context that sends a message to an
#       available cluster node for executing.  When the node reports back that
#       it has completed the task, the callback_event is fired.

sub send_async_event {
    &App::sub_entry if ($App::trace);
    my ($self, $event, $callback_event) = @_;
    my $event_token = $self->send_async_event_in_process($event, $callback_event);
    &App::sub_exit($event_token) if ($App::trace);
    return($event_token);
}

sub send_async_event_in_process {
    &App::sub_entry if ($App::trace);
    my ($self, $event, $callback_event) = @_;
    my $errnum = 0;
    my $errmsg = "";
    my $event_token = "local-$$";
    my ($returnval);
    eval {
        $returnval = $self->send_event($event);
    };
    if ($@) {
        $errmsg = $@;
        $errnum = 1;
        $self->log("ERROR: send_async_event_now() $event->{name}.$event->{method} : $errmsg\n");
    }
    if ($callback_event) {
        $callback_event->{args} = [] if (! $callback_event->{args});
        push(@{$callback_event->{args}}, {event_token => $event_token, returnval => $returnval, errnum => $errnum, errmsg => $errmsg});
        $self->send_event($callback_event);
    }
    &App::sub_exit($event_token) if ($App::trace);
    return($event_token);
}

=head2 wait_for_event()

    * Signature: $self->wait_for_event($event_token)
    * Param:     $event_token     string
    * Return:    void
    * Throws:    App::Exception
    * Since:     0.01

    Sample Usage: 

    $self->wait_for_event($event_token);

The wait_for_event() method is called when an asynchronous event has been
sent and no more processing can be completed before it is done.

=cut

sub wait_for_event {
    &App::sub_entry if ($App::trace);
    my ($self, $event_token) = @_;
    &App::sub_exit() if ($App::trace);
}

# NOTE: This send_message() and send_async_message() can be on the App::Context
#       class to allow a program in any context to send this kind of message.
#       (The only downside is a dependency on IO::Socket::INET.)
sub send_async_message {
    &App::sub_entry if ($App::trace);
    my ($self, $host, $port, $message, $await_return_value, $timeout, $server_close) = @_;
    my $pid = $self->fork();
    if (!$pid) {   # running in child
        $self->send_message($host, $port, $message, $await_return_value, $timeout, $server_close);
        $self->exit(0);
    }
    &App::sub_exit() if ($App::trace);
}

# NOTE: $messages that start with "RV-" wait for a return value.
#       $messages that start with "SC-" force the server to close the socket first
#       This is to help manage which system has the sockets lingering in TIME_WAIT state.
# Here is the truth table for $await_return_value, $server_close
#       $await_return_value  $server_close =         client         +        server     
#       -------------------  -------------   ----------------------   ---------------------
#                 0                0              write/close              read/close
#                 0                1            write/read/close           read/close
#                 1                0         write/read/write/close   read/write/read/close
#                 1                1            write/read/close         read/write/close
sub send_message {
    &App::sub_entry if ($App::trace);
    my ($self, $host, $port, $message, $await_return_value, $timeout, $server_close) = @_;
    my $verbose = $self->{verbose};

    if (!$port && $host =~ /^([^:]+):([0-9]+)$/) {
        $host = $1;
        $port = $2;
    }

    my $send_socket = IO::Socket::INET->new(
        PeerAddr  => $host,
        PeerPort  => $port,
        Proto     => "tcp",
        Type      => SOCK_STREAM,
        ReuseAddr => 1,
    );
    my ($send_fd);
    $send_fd = fileno($send_socket) if ($send_socket);
    $self->log({level=>3},"($send_fd) send_message($host, $port, $message)\n");

    my $response = "";
    my $rv = $await_return_value ? "RV-" : "";
    my $sc = $server_close ? "SC-" : "";
    if ($send_socket) {
        eval {



( run in 3.478 seconds using v1.01-cache-2.11-cpan-5837b0d9d2c )