
Plack::Handler::Stomp - adapt STOMP to (almost) HTTP, via Plack

version 1.05

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());

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.
We consume Net::Stomp::MooseHelpers::CanConnect and Net::Stomp::MooseHelpers::CanSubscribe. Read those modules' documentation to see how to configure servers and subscriptions.

loggerA 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_mapA hashref mapping destinations (queues, topics, subscription ids) to URI paths to send to the application. You should not modify this.
one_shotIf true, exit after the first message is consumed. Useful for testing, defaults to false.

runGiven a PSGI application, loops forever:
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_loopLoop 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_frameDelegates 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_errorLogs the error via the "logger", level warn.
handle_stomp_messageCalls "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_messageRuns 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_receiptLogs (level debug) the receipt id. Nothing else is done with receipts.
maybe_send_replyCalls "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_replyReturns the header X-Reply-Address or X-STOMP-Reply-Address from the response.
send_replyConverts 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_singleafter 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_envBuilds 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.

You can find examples of use in the tests, or at https://github.com/dakkar/CatalystX-StompSampleApps

Gianni Ceccarelli <gianni.ceccarelli@net-a-porter.com>

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.