# You may distribute under the terms of either the GNU General Public License
# or the Artistic License (the same terms as Perl itself)
#
# (C) Paul Evans, 2016-2017 -- leonerd@leonerd.org.uk
package Net::Async::Matrix::Room::State;
use strict;
use warnings;
use List::Util qw( pairmap );
use Struct::Dumb;
struct Member => [qw( user displayname membership )];
our $VERSION = '0.19';
$VERSION = eval $VERSION;
=head1 NAME
C<Net::Async::Matrix::Room::State> - represents the state events in a matrix room
=head1 DESCRIPTION
Instances of this class represent all of the known state events in a
L<Net::Async::Matrix::Room> at some instant in time. These objects are mutable
so a "live" state object obtained from a room will change to keep track of
newly received state events.
=cut
sub new
{
my $class = shift;
my ( $room ) = @_;
return bless {
events => {},
matrix => $room->{matrix},
}, $class;
}
sub handle_event
{
my $self = shift;
my ( $event ) = @_;
defined $event->{state_key} or return;
my $type = $event->{type};
my $state_key = $event->{state_key} // "";
$self->{events}{$type}{$state_key} = $event;
}
=head1 METHODS
=cut
=head2 get_event
$event = $state->get_event( $type, $state_key )
Returns a HASH reference containing the raw event stored for the given type
name and optional state key.
=cut
sub get_event
{
my $self = shift;
my ( $type, $state_key ) = @_;
$state_key //= "";
return $self->{events}{$type}{$state_key};
}
=head2 get_events
$events = $state->get_events( $type )
Returns a multi-level HASH reference mapping all of the known state keys for a
given event type name to their raw stored events. Typically this is useful for
C<m.room.member> events as the state keys will be user IDs.
=cut
sub get_events
{
my $self = shift;
my ( $type ) = @_;
return $self->{events}{$type} // {};
}
=head1 CONVENIENCE ACCESSORS
The following accessors all fetch single values out of certain events, as they
are commonly used.
=cut
=head2 name
$name = $state->name
Returns the C<name> field of the C<m.room.name> event, if it exists.
=cut
sub name
{
my $self = shift;
my $event = $self->get_event( "m.room.name" ) or return undef;
return $event->{content}{name};
}
=head2 join_rule
$join_rule = $state->join_rule
Returns the C<join_rule> field of the C<m.room.join_rules> event, if it
exists.
=cut
sub join_rule
{
my $self = shift;
my $event = $self->get_event( "m.room.join_rules" ) or return undef;
return $event->{content}{join_rule};
}
=head2 topic
$topic = $state->topic
Returns the C<topic> field of the C<m.room.topic> event, if it exists.
=cut
sub topic
{
my $self = shift;
my $event = $self->get_event( "m.room.topic" ) or return undef;
return $event->{content}{topic};
}
=head2 aliases
@aliases = $state->aliases
Returns a list of the room alias from all the C<m.room.aliases> events, in no
particular order.
=cut
sub aliases
{
my $self = shift;
return map { @{ $_->{content}{aliases} } }
values %{ $self->get_events( "m.room.aliases" ) };
}
=head2 members
@members = $state->members
Returns a list of Member instances representing all of the members of the room
from the C<m.room.member> events whose membership state is not C<leave>.
=cut
sub members
{
my $self = shift;
my ( $with_leaves ) = @_;
return pairmap {
my ( $user_id, $event ) = ( $a, $b );
my $content = $event->{content};
return () if $content->{membership} eq "leave" and !$with_leaves;
my $user = $self->{matrix}->_get_or_make_user( $user_id );
Member( $user, $content->{displayname}, $content->{membership} );
} %{ $self->get_events( "m.room.member" ) };
}
=head2 all_members
@members = $state->members
Similar to L</members> but even includes members in C<leave> state. This is
not normally what you want.
=cut
sub all_members
{
my $self = shift;
return $self->members( 1 );
}
=head2 member
$member = $state->member( $user_id )
Returns a Member instance representing a room member of the given user ID, or
C<undef> if none exists.
=cut
sub member
{
my $self = shift;
my ( $user_id ) = @_;
my $event = $self->get_event( "m.room.member", $user_id ) or return undef;
my $user = $self->{matrix}->_get_or_make_user( $user_id );
my $content = $event->{content};
return Member( $user, $content->{displayname}, $content->{membership} );
}
=head2 member_level
$level = $state->member_level( $user_id )
Returns a number indicating the power level that the given user ID would have
according to room state, taken from the C<m.room.power_levels> event. This
takes into account the C<users_default> field, if no specific level exists for
the given user ID.
=cut
sub member_level
{
my $self = shift;
my ( $user_id ) = @_;
my $event = $self->get_event( "m.room.power_levels" ) or return undef;
my $levels = $event->{content};
return $levels->{users}{$user_id} // $levels->{users_default};
}
=head1 AUTHOR
Paul Evans <leonerd@leonerd.org.uk>
=cut
0x55AA;