File Coverage

blib/lib/Circle/Net/Matrix.pm
Criterion Covered Total %
statement 30 119 25.2
branch 0 10 0.0
condition 0 3 0.0
subroutine 10 29 34.4
pod 0 15 0.0
total 40 176 22.7


line stmt bran cond sub pod time code
1             # You may distribute under the terms of the GNU General Public License
2             #
3             # (C) Paul Evans, 2014-2017 -- leonerd@leonerd.org.uk
4              
5             package Circle::Net::Matrix;
6              
7 1     1   776 use strict;
  1         1  
  1         32  
8 1     1   4 use warnings;
  1         2  
  1         43  
9 1     1   15 use base qw( Circle::Net );
  1         2  
  1         572  
10              
11             our $VERSION = '0.03';
12              
13             require Circle;
14             Circle->VERSION( '0.142470' ); # require late-loading of Tangence::Class
15              
16 1     1   69625 use constant NETTYPE => 'matrix';
  1         1  
  1         53  
17              
18 1     1   3 use Circle::Widget::Box;
  1         2  
  1         19  
19 1     1   385 use Circle::Widget::Label;
  1         119  
  1         25  
20              
21 1     1   4 use Data::Dump qw( pp );
  1         1  
  1         42  
22 1     1   3 use Scalar::Util qw( weaken );
  1         1  
  1         676  
23              
24             =head1 NAME
25              
26             C - use C as a I client
27              
28             =head1 SYNOPSIS
29              
30             On the global tab:
31              
32             /networks add -type matrix Matrix
33              
34             On the newly-added "Matrix" tab:
35              
36             /set homeserver example.com
37             /set user_id @me:example.com
38             /set access_token MDAxABCDE...
39              
40             /connect
41              
42             (for now you'll have to log in and steal and access token from another Matrix
43             client; for example L).
44              
45             =cut
46              
47             # To allow for out-of-tree development, use an inline Tangence class
48             # declaration instead of a .tan file
49             #
50             # class Circle.Net.Matrix {
51             # isa Circle.WindowItem;
52             # }
53              
54             sub DECLARE_TANGENCE
55             {
56 0     0 0   Tangence::Class->declare( __PACKAGE__,
57             superclasses => [qw( Circle::WindowItem )],
58             );
59              
60             # Also load the other classes
61 0           require Circle::Net::Matrix::Room;
62 0           Circle::Net::Matrix::Room->DECLARE_TANGENCE;
63              
64 0           require Net::Async::Matrix;
65 0           Net::Async::Matrix->VERSION( '0.18003' );
66             }
67              
68             sub WEAKSELF_EVAL
69             {
70 0     0 0   my ( $self, $method ) = @_;
71 0 0   0     my $code = $self->can( $method ) or return sub {};
72              
73 0           weaken( $self );
74             return sub {
75 0     0     my @args = @_;
76 0 0         eval { $self->$code( @args ); 1 } or
  0            
  0            
77             warn $@;
78 0           };
79             }
80              
81             sub new
82             {
83 0     0 0   my $class = shift;
84 0           my %args = @_;
85              
86 0           my $self = $class->SUPER::new( %args );
87              
88 0           $self->{root} = $args{root};
89 0           my $loop = $self->{loop} = $args{loop};
90              
91             # For WindowItem
92 0           $self->set_prop_tag( $args{tag} );
93              
94 0           weaken( my $weakself = $self );
95             my $matrix = $self->{matrix} = Net::Async::Matrix->new(
96       0     on_log => sub { }, # TODO
97 0           on_presence => $self->WEAKSELF_EVAL( 'on_presence' ),
98             on_room_new => $self->WEAKSELF_EVAL( 'on_room_new' ),
99             on_room_del => $self->WEAKSELF_EVAL( 'on_room_del' ),
100              
101             on_error => $self->WEAKSELF_EVAL( 'on_error' ),
102             );
103              
104 0           $loop->add( $matrix );
105              
106 0           $self->set_network_status( "disconnected" );
107              
108 0           return $self;
109             }
110              
111             sub on_error
112             {
113 0     0 0   my $self = shift; shift;
  0            
114 0           my ( $message ) = @_;
115              
116 0           $self->push_displayevent( error => { text => $message } );
117 0           $self->bump_level( 3 );
118             }
119              
120             sub parent
121             {
122 0     0 0   my $self = shift;
123 0           return $self->{root};
124             }
125              
126             sub enumerable_name
127             {
128 0     0 0   my $self = shift;
129 0           return $self->get_prop_tag;
130             }
131              
132             sub commandable_parent
133             {
134 0     0 0   my $self = shift;
135 0           return $self->{root};
136             }
137              
138             sub get_room_or_create
139             {
140 0     0 0   my $self = shift;
141 0           my ( $room ) = @_;
142              
143 0           my $room_id = $room->room_id;
144              
145 0 0         return $self->{rooms}{$room_id} if exists $self->{rooms}{$room_id};
146              
147 0           my $registry = $self->{registry};
148 0           my $root = $self->{root};
149              
150 0           my $roomobj = $registry->construct(
151             "Circle::Net::Matrix::Room",
152             root => $root,
153             net => $self,
154             room => $room,
155             );
156 0           $self->{rooms}{$room_id} = $roomobj;
157              
158 0           $root->broadcast_sessions( new_item => $roomobj );
159              
160 0           return $roomobj;
161             }
162              
163             sub on_room_new
164             {
165 0     0 0   my $self = shift; shift;
  0            
166 0           my ( $room ) = @_;
167              
168 0           $self->get_room_or_create( $room );
169             }
170              
171             sub on_room_del
172             {
173 0     0 0   my $self = shift; shift;
  0            
174 0           my ( $room ) = @_;
175              
176 0 0         my $roomobj = delete $self->{rooms}{$room->room_id} or return;
177            
178 0           $self->{root}->broadcast_sessions( delete_item => $roomobj );
179 0           $roomobj->destroy;
180             }
181              
182             sub on_presence
183             {
184 0     0 0   my $self = shift; shift;
  0            
185 0           my ( $user, %changes ) = @_;
186              
187             # Ignore for now
188             #$self->push_displayevent( "text", {
189             # text => "User ${\$user->user_id} presence change " . pp(\%changes),
190             #});
191             }
192              
193             __PACKAGE__->APPLY_Setting( homeserver =>
194             description => "Hostname of the homeserver",
195             type => 'str',
196             );
197              
198             __PACKAGE__->APPLY_Setting( user_id =>
199             description => "User ID to use",
200             type => 'str',
201             );
202              
203             __PACKAGE__->APPLY_Setting( access_token =>
204             description => "Access Token of the user",
205             type => 'str',
206             );
207              
208             __PACKAGE__->APPLY_Setting( initial_backlog =>
209             description => "Initial size of backlog to request per room",
210             type => "int",
211             default => 100,
212             );
213              
214             sub command_connect
215             : Command_description("Connect to the homeserver")
216             : Command_arg('homeserver?')
217             {
218 0     0 0 0 my $self = shift;
219 0         0 my ( $homeserver, $cinv ) = @_;
220              
221 0 0       0 $homeserver = $self->{homeserver} unless defined $homeserver;
222              
223 0         0 my $matrix = $self->{matrix};
224             $matrix->configure(
225             server => $homeserver,
226             first_sync_limit => $self->{initial_backlog},
227 0         0 );
228              
229             # TODO: would be nice if Circle could cope with Future-returning
230             # command subs...
231              
232 0         0 $self->push_displayevent( "status", { text => "logging in" } );
233 0         0 $self->set_network_status( "logging in" );
234              
235             my $f = $matrix->login(
236             user_id => $self->{user_id},
237             access_token => $self->{access_token},
238             )->on_done( sub {
239 0     0   0 $self->push_displayevent( "status", { text => "syncing..." } );
240 0         0 $self->set_network_status( "syncing" );
241              
242             $matrix->start->on_done( sub {
243 0         0 $self->set_network_status( "" );
244 0         0 });
245 0         0 });
246              
247 0         0 $matrix->adopt_future( $f );
248              
249 0         0 return ();
250 1     1   4 }
  1         2  
  1         4  
251              
252             sub command_join
253             : Command_description("Join a named room")
254             : Command_arg('roomname')
255             {
256 0     0 0   my $self = shift;
257 0           my ( $roomname, $cinv ) = @_;
258              
259 0           my $matrix = $self->{matrix};
260              
261 0           $matrix->join_room( $roomname );
262              
263 0           return;
264 1     1   636 }
  1         2  
  1         3  
265              
266             ###
267             # Widgets
268             ###
269              
270             sub get_widget_my_displayname
271             {
272 0     0 0   my $self = shift;
273              
274 0   0       return $self->{widget_displayname} ||= do {
275 0           my $registry = $self->{registry};
276              
277 0           my $widget = $registry->construct(
278             "Circle::Widget::Label",
279             classes => [qw( nick )],
280             );
281              
282 0           $widget->set_prop_text( $self->{matrix}->myself->displayname );
283              
284 0           $widget;
285             };
286             }
287              
288             sub get_widget_statusbar
289             {
290 0     0 0   my $self = shift;
291              
292 0           my $registry = $self->{registry};
293              
294 0           my $statusbar = $registry->construct(
295             "Circle::Widget::Box",
296             classes => [qw( status )],
297             orientation => "horizontal",
298             );
299              
300 0           $statusbar->add( $self->get_widget_netname );
301              
302 0           $statusbar->add( $self->get_widget_my_displayname );
303              
304             # $statusbar->add( $self->get_widget_presence );
305              
306 0           return $statusbar;
307             }
308              
309             =head1 AUTHOR
310              
311             Paul Evans
312              
313             =cut
314              
315             0x55AA;