[djabberd] mart,
r550: Basic support for in-process "components...
Artur Bergman
sky at crucially.net
Sat Jul 8 17:00:28 UTC 2006
The register_subdomain function is slated for deprecation because I
want to kill subdomains to make the code easier, so you will have to
declare the vhost and then tell the component to take it over
completely.
I also don't like the indirection classes, why cannot Component.pm be
a Plugin.pm?
Artur
On Jul 8, 2006, at 7:34 AM, commits at code.sixapart.com wrote:
> Basic support for in-process "components".
>
> Here I'm defining a component as an agent that handles JIDs for an
> entire domain. This is differs from a bot, which handles only a
> single node.
>
> A plugin is provided for making a component appear as a subdomain
> of a vhost. However, the component subclasses don't really care
> what calls them so you could theoretically make a Delivery plugin
> that turns an entire VHost into a component, or whatever.
>
>
> A trunk/lib/DJabberd/Component/
> A trunk/lib/DJabberd/Component/Example.pm
> A trunk/lib/DJabberd/Component.pm
> A trunk/lib/DJabberd/Plugin/Component.pm
>
>
> Added: trunk/lib/DJabberd/Component/Example.pm
> ===================================================================
> --- trunk/lib/DJabberd/Component/Example.pm 2006-07-08 11:26:31 UTC
> (rev 549)
> +++ trunk/lib/DJabberd/Component/Example.pm 2006-07-08 14:34:02 UTC
> (rev 550)
> @@ -0,0 +1,107 @@
> +
> +
> +=head1 NAME
> +
> +DJabberd::Component::Example - An example DJabberd service component
> +
> +=head1 SYNOPSIS
> +
> + <Plugin DJabberd::Plugin::Component>
> + Subdomain example
> + Class DJabberd::Component::Example
> + Greeting Hello, world!
> + </Plugin>
> +
> +This class implements a very simple component that responds to all
> incoming messages
> +with a predefined greeting and which returns a vCard for itself
> when one is requested.
> +You can change the greeting returned using the optional Greeting
> configuration setting
> +as above.
> +
> +=cut
> +
> +package DJabberd::Component::Example;
> +use base DJabberd::Component;
> +use DJabberd::Util qw(exml);
> +use DJabberd::Log;
> +
> +our $logger = DJabberd::Log->get_logger();
> +
> +sub initialize {
> + my ($self, $opts) = @_;
> +
> + $self->{greeting} = $opts->{greeting} || "Hi! I'm an example
> DJabberd component!";
> +}
> +
> +sub handle_stanza {
> + my ($self, $vhost, $cb, $stanza) = @_;
> +
> + $logger->info("Got stanza: ".$stanza->as_summary);
> +
> + # We only want stanzas addressed to the domain, since there
> + # aren't any nodes under this component.
> + if ($stanza->to_jid->as_string ne $self->domain) {
> + $logger->info("Message to ".$stanza->to_jid->as_string.",
> not ".$self->domain.". Discarding.");
> + $cb->decline;
> + return;
> + }
> +
> + if ($stanza->isa('DJabberd::IQ')) {
> +
> + if ($stanza->signature eq 'get-{vcard-temp}vCard') {
> +
> + $logger->info("Got vCard request from ".$stanza-
> >from_jid->as_string);
> +
> + my $response = $self->_make_response($stanza);
> + $response->attrs->{"{}type"} = "result";
> + $response->set_raw("<vCard xmlns='vcard-
> temp'><FN>Example DJabberd component</FN></vCard>");
> + $logger->info("Responding with ".$response->as_xml);
> + $response->deliver($vhost);
> +
> + $cb->delivered;
> + return;
> +
> + }
> + else {
> + $logger->info("Got unrecognized IQ stanza from ".
> $stanza->from_jid->as_string);
> + $cb->decline;
> + return;
> + }
> + }
> + elsif ($stanza->isa('DJabberd::Message')) {
> + my $from = $stanza->from_jid;
> +
> + $logger->info("Got message from ".$from->as_string);
> +
> + my $response = $self->_make_response($stanza);
> +
> + $response->attrs->{"{}type"} = "normal";
> + $response->set_raw("<body>".exml($self->{greeting})."</
> body>");
> +
> + $logger->info("Responding with ".$response->as_xml);
> +
> + $response->deliver($vhost);
> +
> + $cb->delivered;
> + return;
> + }
> +
> + $logger->info("I don't know what to do with $stanza");
> + $cb->decline;
> +}
> +
> +
> +sub _make_response {
> + my ($self, $stanza) = @_;
> +
> + my $response = $stanza->clone;
> + my $from = $stanza->from;
> + my $to = $stanza->to;
> +
> + $response->set_to($from);
> + $to ? $response->set_from($to) : delete($response->attrs->{"{}
> from"});
> +
> + return $response;
> +}
> +
> +
> +1;
>
> Added: trunk/lib/DJabberd/Component.pm
> ===================================================================
> --- trunk/lib/DJabberd/Component.pm 2006-07-08 11:26:31 UTC (rev 549)
> +++ trunk/lib/DJabberd/Component.pm 2006-07-08 14:34:02 UTC (rev 550)
> @@ -0,0 +1,65 @@
> +
> +=head1 NAME
> +
> +DJabberd::Component - Abstract class representing a component in
> DJabberd
> +
> +=head1 SYNOPSIS
> +
> + package MyPackage::DJabberd::MyComponent;
> + use base DJabberd::Component;
> +
> + sub initialize {
> + my ($self, $opts) = @_;
> +
> + # ... perform initialization
> + }
> +
> + sub handle_stanza {
> + my ($self, $vhost, $cb, $stanza) = @_;
> +
> + # ... handle the given stanza
> + }
> +
> +This class provides a parent class for all DJabberd components.
> Components
> +that inherit from this class can then be used directly by the
> server via the
> +DJabberd::Plugin::Component plugin, or used directly by other
> classes.
> +
> +See DJabberd::Component::Example for an example component
> implementation.
> +
> +TODO: Write more docs
> +
> +=cut
> +
> +package DJabberd::Component;
> +
> +use strict;
> +use DJabberd::Log;
> +
> +our $logger = DJabberd::Log->get_logger();
> +
> +sub new {
> + my ($class, $domain, $opts) = @_;
> +
> + my $self = bless {
> + _component_domain => $domain,
> + }, $class;
> +
> + $self->initialize($opts);
> +
> + return $self;
> +}
> +
> +sub initialize { }
> +
> +sub domain {
> + return $_[1] ? $_[0]->{_component_domain} = $_[1] : $_[0]->
> {_component_domain};
> +}
> +
> +sub handle_stanza {
> + my ($self, $vhost, $cb, $stanza) = @_;
> +
> + $logger->warn("handle_stanza not implemented for $self");
> + $cb->decline;
> +}
> +
> +1;
>
> Added: trunk/lib/DJabberd/Plugin/Component.pm
> ===================================================================
> --- trunk/lib/DJabberd/Plugin/Component.pm 2006-07-08 11:26:31 UTC
> (rev 549)
> +++ trunk/lib/DJabberd/Plugin/Component.pm 2006-07-08 14:34:02 UTC
> (rev 550)
> @@ -0,0 +1,61 @@
> +
> +package DJabberd::Plugin::Component;
> +
> +use strict;
> +use base 'DJabberd::Plugin';
> +use warnings;
> +use Carp;
> +our $logger = DJabberd::Log->get_logger();
> +
> +
> +sub set_config_subdomain {
> + my ($self, $subdomain) = @_;
> + $self->{subdomain} = $subdomain;
> +}
> +
> +sub set_config_class {
> + my ($self, $class) = @_;
> + $logger->logdie("Invalid classname $class") if $class =~ /[^
> \w:]/;
> + $self->{class} = $class;
> +}
> +
> +# Pass any unrecognised configuration parameters on to the
> component itself
> +sub set_config__option {
> + my ($self, $key, $val) = @_;
> + $self->{component_opts} ||= {};
> + $self->{component_opts}{$key} = $val;
> +}
> +
> +sub finalize {
> + my ($self) = @_;
> +
> + $logger->logdie("The Class directive is required") unless
> $self->{class};
> + $logger->logdie("The Subdomain directive is required") unless
> $self->{subdomain};
> +
> + my $loaded = eval "use $self->{class}; 1;";
> + $logger->logdie("Unable to load component class $self->
> {class}: $@") unless $loaded;
> +}
> +
> +sub register {
> + my ($self, $vhost) = @_;
> +
> + $self->{domain} = $self->{subdomain} . "." . $vhost->server_name;
> + $vhost->register_subdomain($self->{subdomain}, __PACKAGE__);
> +
> + $self->{component} = $self->{class}->new($self->{domain},
> $self->{component_opts});
> + $logger->logdie("Failed to instantiate component $self->
> {class}") unless ref $self->{component};
> +
> + $logger->info("Attaching component $self->{domain} ($self->
> {class})");
> +
> + $self->{vhost} = $vhost;
> + Scalar::Util::weaken($self->{vhost});
> +
> + $vhost->register_hook('deliver',sub {
> + if ($_[2]->to_jid && $_[2]->to_jid->domain eq $self->
> {domain}) {
> + $logger->debug("Delivering ".$_[2]->element_name."
> stanza to component ".$self->{domain});
> + $self->{component}->handle_stanza(@_);
> + }
> + });
> +}
> +
> +1;
>
>
More information about the Djabberd
mailing list