NAME
Plack::Handler::Stomp - adapt STOMP to (almost) HTTP, via Plack
VERSION
version 1.07
SYNOPSIS
my $runner = Plack::Handler::Stomp->new({
servers => [ { hostname => 'localhost', port => 61613 } ],
subscriptions => [
{ destination => '/queue/plack-handler-stomp-test' },
{ destination => '/topic/plack-handler-stomp-test',
headers => {
selector => q{custom_header = '1' or JMSType = 'test_foo'},
},
path_info => '/topic/ch1', },
{ destination => '/topic/plack-handler-stomp-test',
headers => {
selector => q{custom_header = '2' or JMSType = 'test_bar'},
},
path_info => '/topic/ch2', },
],
});
$runner->run(MyApp->get_app());
DESCRIPTION
Sometimes you want to use your very nice web-application-framework dispatcher, module loading mechanisms, etc, but you're not really writing a web application, you're writing a ActiveMQ consumer. In those cases, this module is for you.
This module is inspired by Catalyst::Engine::Stomp, but aims to be usable by any PSGI application.
Roles Consumed
We consume Net::Stomp::MooseHelpers::CanConnect and Net::Stomp::MooseHelpers::CanSubscribe. Read those modules' documentation to see how to configure servers and subscriptions.
ATTRIBUTES
logger
A logger object used by thes handler. Not to be confused by the logger used by the application (either internally, or via a Middleware). Can be any object that can debug
, info
, warn
, error
. Defaults to an instance of Plack::Handler::Stomp::StupidLogger.
destination_path_map
A hashref mapping destinations (queues, topics, subscription ids) to URI paths to send to the application. You should not modify this.
one_shot
If true, exit after the first message is consumed. Useful for testing, defaults to false.
METHODS
run
Given a PSGI application, loops forever:
connect to a STOMP server (see connect and servers in Net::Stomp::MooseHelpers::CanConnect)
subscribe to whatever needed (see subscribe and subscriptions in Net::Stomp::MooseHelpers::CanSubscribe)
consume STOMP frames in an inner loop (see "frame_loop")
If the application throws an exception, the loop exits re-throwing the exception. If the STOMP connection has problems, the loop is repeated with a different server (see next_server in Net::Stomp::MooseHelpers::CanConnect).
If "one_shot" is set, this function exits after having consumed exactly 1 frame.
frame_loop
Loop forever receiving frames from the STOMP connection. Call "handle_stomp_frame" for each frame.
If "one_shot" is set, this function exits after having consumed exactly 1 frame.
handle_stomp_frame
Delegates the handling to "handle_stomp_message", "handle_stomp_error", "handle_stomp_receipt", or throws Plack::Handler::Stomp::Exceptions::UnknownFrame if the frame is of some other kind. If you want to handle different kind of frames (maybe because you have some non-standard STOMP server), you can just subclass and add methods; for example, to handle STRANGE
frames, add a handle_stomp_strange
method.
handle_stomp_error
Logs the error via the "logger", level warn
.
handle_stomp_message
Calls "build_psgi_env" to convert the STOMP message into a PSGI environment.
The environment is then passed to "process_the_message", and the frame is acknowledged.
process_the_message
Runs a PSGI environment through the application, then flattens the response body into a simple string.
The response so flattened is sent back via "maybe_send_reply".
handle_stomp_receipt
Logs (level debug
) the receipt id. Nothing else is done with receipts.
maybe_send_reply
Calls "where_should_send_reply" to determine if to send a reply, and where. If it returns a true value, "send_reply" is called to actually send the reply.
where_should_send_reply
Returns the header X-Reply-Address
or X-STOMP-Reply-Address
from the response.
send_reply
Converts the PSGI response into a STOMP frame, by removing the prefix x-stomp-
from the key of header fields that have it, removing entirely header fields that don't, and stringifying the body.
Then sends the frame.
subscribe_single
after
modifier on the method provided by Net::Stomp::MooseHelpers::CanSubscribe.
It sets the "destination_path_map" to map the destination and the subscription id to the path_info
slot of the "subscriptions" element, or to the destination itself if path_info
is not defined.
build_psgi_env
Builds a PSGI environment from the message, like:
# server
SERVER_NAME => 'localhost',
SERVER_PORT => 0,
SERVER_PROTOCOL => 'STOMP',
# client
REQUEST_METHOD => 'POST',
REQUEST_URI => $path_info,
SCRIPT_NAME => '',
PATH_INFO => $path_info,
QUERY_STRING => '',
# broker
REMOTE_ADDR => $server_hostname,
# http
HTTP_USER_AGENT => 'Net::Stomp',
HTTP_CONTENT_LENGTH => length($body),
HTTP_CONTENT_TYPE => $content-type,
# psgi
'psgi.version' => [1,0],
'psgi.url_scheme' => 'http',
'psgi.multithread' => 0,
'psgi.multiprocess' => 0,
'psgi.run_once' => 0,
'psgi.nonblocking' => 0,
'psgi.streaming' => 1,
In addition, reading from psgi.input
will return the message body, and writing to psgi.errors
will log via the "logger" at level error
.
Finally, every header in the STOMP message will be available in the "namespace" jms.
, so for example the message type is in jms.type
.
The $path_info
is obtained from the "destination_path_map" (i.e. from the path_info
subscription options) passed through munge_path_info.
EXAMPLES
You can find examples of use in the tests, or at https://github.com/dakkar/CatalystX-StompSampleApps
AUTHOR
Gianni Ceccarelli <gianni.ceccarelli@net-a-porter.com>
COPYRIGHT AND LICENSE
This software is copyright (c) 2012 by Net-a-porter.com.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.