aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Matrix/Client.pm620
-rw-r--r--lib/Matrix/Client/Exception.pm66
-rw-r--r--lib/Matrix/Client/MediaStore.rakumod116
-rw-r--r--lib/Matrix/Client/Requester.pm62
-rw-r--r--lib/Matrix/Client/Room.pm6138
-rw-r--r--lib/Matrix/Response.pm619
6 files changed, 263 insertions, 38 deletions
diff --git a/lib/Matrix/Client.pm6 b/lib/Matrix/Client.pm6
index 9022c65..2e26ee7 100644
--- a/lib/Matrix/Client.pm6
+++ b/lib/Matrix/Client.pm6
@@ -5,6 +5,7 @@ use Matrix::Response;
use Matrix::Client::Common;
use Matrix::Client::Room;
use Matrix::Client::Requester;
+use Matrix::Client::MediaStore;
unit class Matrix::Client does Matrix::Client::Requester;
@@ -331,16 +332,15 @@ method remove-room-alias($room-alias) {
# Media
-#| POST - /_matrix/media/r0/upload
-method upload(IO::Path $path, Str $filename?) {
- my $buf = slurp $path, :bin;
- my $fn = $filename ?? $filename !! $path.basename;
- my $res = $.post-bin("/upload", $buf,
- content-type => "image/png",
- filename => $fn,
- );
- my $data = from-json($res.content);
- $data<content_uri> // "";
+method media(--> Matrix::Client::MediaStore) {
+ return Matrix::Client::MediaStore.new(
+ home-server => $!home-server,
+ access-token => $!access-token
+ )
+}
+
+method upload(IO::Path $path, Str $filename?) is DEPRECATED('media.upload') {
+ self.media.upload($path, $filename)
}
# Misc
diff --git a/lib/Matrix/Client/Exception.pm6 b/lib/Matrix/Client/Exception.pm6
index 924eece..e02f572 100644
--- a/lib/Matrix/Client/Exception.pm6
+++ b/lib/Matrix/Client/Exception.pm6
@@ -7,4 +7,10 @@ package X::Matrix {
"$!code: $!error"
}
}
+
+ class MXCParse is Exception {
+ has $.uri;
+
+ method message { "Cannot parse '$!uri'" }
+ }
}
diff --git a/lib/Matrix/Client/MediaStore.rakumod b/lib/Matrix/Client/MediaStore.rakumod
new file mode 100644
index 0000000..9779db2
--- /dev/null
+++ b/lib/Matrix/Client/MediaStore.rakumod
@@ -0,0 +1,116 @@
+use JSON::Fast;
+use URI::Escape;
+
+use Matrix::Client::Requester;
+use Matrix::Client::Exception;
+use Matrix::Response;
+
+unit class Matrix::Client::MediaStore does Matrix::Client::Requester;
+
+class Matrix::Client::MediaStore::File {
+ has Str $.content-type;
+ has Str $.content-disposition;
+ has Buf $.content;
+}
+
+submethod TWEAK {
+ # Different client endpoint for media
+ $!client-endpoint = "/_matrix/media/r0";
+}
+
+method parse-mxc(Str $uri) {
+ if $uri ~~ m/"mxc://" $<server-name> = [.*] "/" $<media-id> = [ .* ]/ {
+ return {
+ server-name => $<server-name>,
+ media-id => $<media-id>
+ }
+ }
+
+ X::Matrix::MXCParse.new(:$uri).throw;
+}
+
+#| POST - /_matrix/media/r0/upload
+method upload(IO::Path $path, Str $filename?, Str :$content-type is copy = "image/png" --> Str) {
+ my $buf = slurp $path, :bin;
+ my $fn = $filename ?? $filename !! $path.basename;
+
+ # The filename is passed on a query param.
+ my $endpoint = "/upload?filename=" ~ uri-escape($fn);
+
+
+ my $res = $.post-bin(
+ $endpoint, $buf,
+ :$content-type,
+ );
+
+ my $data = from-json($res.content);
+ $data<content_uri> // "";
+}
+
+#| GET - /_matrix/media/r0/download/{serverName}/{mediaId}
+multi method download(Str $mxc-uri, :$allow-remote = True, Str :$filename?) {
+ my $mxc = self.parse-mxc($mxc-uri);
+
+ samewith($mxc<server-name>, $mxc<media-id>, :$allow-remote, :$filename)
+}
+
+#| GET - /_matrix/media/r0/download/{serverName}/{mediaId}/{fileName}
+multi method download(Str $server-name, Str $media-id,
+ Bool :$allow-remote = True, Str :$filename?) {
+ my $endpoint = "/download/{$server-name}/{$media-id}";
+
+ $endpoint ~= "/{$filename}" if $filename.defined;
+ my $response = $.get(
+ $endpoint,
+ allow_remote => $allow-remote.Str.lc
+ );
+
+ my %headers = $response.header.hash();
+
+ Matrix::Client::MediaStore::File.new(
+ content-type => %headers<Content-Type>.head,
+ content-disposition => %headers<Content-Disposition>.head,
+ content => $response.content
+ )
+}
+
+#| GET - /_matrix/media/r0/thumbnail/{serverName}/{mediaId}
+multi method thumbnail(Str $mxc-uri, Int $width, Int $height,
+ Str :$method where * eq 'crop'|'scale',
+ Bool :$allow-remote = True) {
+ my $mxc = self.parse-mxc($mxc-uri);
+ samewith(
+ $mxc<server-name>, $mxc<media-id>,
+ $width, $height,
+ :$method, :$allow-remote
+ )
+}
+
+#| GET - /_matrix/media/r0/thumbnail/{serverName}/{mediaId}
+multi method thumbnail(Str $server-name, Str $media-id,
+ Int $width, Int $height,
+ Str :$method where * eq 'crop'|'scale',
+ Bool :$allow-remote = True) {
+ my $endpoint = "/thumbnail/{$server-name}/{$media-id}";
+
+ my $response = $.get(
+ $endpoint,
+ :$height,
+ :$width,
+ :$method,
+ allow_remote => $allow-remote.Str.lc
+ );
+
+ my %headers = $response.header.hash();
+
+ Matrix::Client::MediaStore::File.new(
+ content-type => %headers<Content-Type>.head,
+ content => $response.content
+ )
+}
+
+#| GET - /_matrix/media/r0/config
+method config(--> Matrix::Response::MediaStore::Config) {
+ my $response = $.get("/config");
+ Matrix::Response::MediaStore::Config.new(from-json($response.content))
+}
diff --git a/lib/Matrix/Client/Requester.pm6 b/lib/Matrix/Client/Requester.pm6
index ff543c9..36a9f69 100644
--- a/lib/Matrix/Client/Requester.pm6
+++ b/lib/Matrix/Client/Requester.pm6
@@ -73,7 +73,7 @@ multi method post(Str $path, :$media = False, *%params) {
method post-bin(Str $path, Buf $buf, :$content-type) {
my $encoded-path = $path.subst('#', '%23');
my $req = POST(
- $.base-url(:media) ~ $encoded-path,
+ $.base-url() ~ $encoded-path,
content => $buf,
Content-Type => $content-type
);
diff --git a/lib/Matrix/Client/Room.pm6 b/lib/Matrix/Client/Room.pm6
index ca97d2f..3d6ecaa 100644
--- a/lib/Matrix/Client/Room.pm6
+++ b/lib/Matrix/Client/Room.pm6
@@ -25,15 +25,8 @@ method !get-name() {
$!name = $data<name>;
}
-#| GET - /_matrix/client/r0/rooms/{roomId}/joined_members
-method joined-members {
- my %data = from-json($.get("/joined_members").content);
- %data<joined>
-}
-
-method name {
+method name(--> Str) {
self!get-name;
-
$!name
}
@@ -52,23 +45,20 @@ method fallback-name(--> Str) {
};
}
-#| GET - /_matrix/client/r0/rooms/{roomId}/messages
-method messages() {
- my $res = $.get("/messages");
- my $data = from-json($res.content);
-
- return $data<chunk>.clone;
+#| GET - /_matrix/client/r0/rooms/{roomId}/aliases
+method aliases(--> List) {
+ my %data = from-json($.get('/aliases').content);
+ %data<aliases>.List
}
-#| PUT - /_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}
-method send(Str $body!, Str :$type? = "m.text") {
- $Matrix::Client::Common::TXN-ID++;
- my $res = $.put(
- "/send/m.room.message/{$Matrix::Client::Common::TXN-ID}",
- msgtype => $type, body => $body
- );
+# Events
- from-json($res.content)<event_id>
+## Getting events for a room
+
+#| GET - /_matrix/client/r0/rooms/{roomId}/event/{eventId}
+method event(Str $event-id --> Matrix::Response::RoomEvent) {
+ my %data = from-json($.get("/event/$event-id").content);
+ Matrix::Response::RoomEvent.new(|%data)
}
#| GET - /_matrix/client/r0/rooms/{roomId}/state
@@ -80,9 +70,67 @@ multi method state(--> Seq) {
}
}
-#| GET - /_matrix/client/r0/rooms/{roomId}/state/{eventType}
-multi method state(Str $event-type) {
- from-json($.get("/state/$event-type").content)
+#| GET - /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}
+multi method state(Str $event-type, Str $state-key = "") {
+ from-json($.get("/state/$event-type/$state-key").content)
+}
+
+#| GET - /_matrix/client/r0/rooms/{roomId}/joined_members
+method joined-members {
+ my %data = from-json($.get("/joined_members").content);
+ %data<joined>
+}
+
+#| GET - /_matrix/client/r0/rooms/{roomId}/messages
+method messages(
+ Str:D :$from!, Str :$to,
+ Str :$dir where * eq 'f'|'b' = 'f',
+ Int :$limit = 10, :%filter,
+ --> Matrix::Response::Messages
+) {
+ my $res = $.get(
+ "/messages", :$from, :$to, :$dir, :$limit, :%filter
+ );
+ my $data = from-json($res.content);
+
+
+ my @messages = $data<chunk>.map(-> $ev {
+ Matrix::Response::RoomEvent.new(|$ev)
+ });
+
+ Matrix::Response::Messages.new(
+ start => $data<start>,
+ end => $data<end>,
+ messages => @messages
+ )
+}
+
+#| GET - /_matrix/client/r0/rooms/{roomId}/members
+method members(:$at, Str :$membership, Str :$not-membership --> Seq) {
+ my %query;
+
+ %query<at> = $at with $at;
+ %query<membership> = $membership with $membership;
+ %query<not_membership> = $not-membership with $not-membership;
+
+ my %data = from-json($.get('/members', |%query).content);
+
+ gather for %data<chunk>.List -> $ev {
+ take Matrix::Response::MemberEvent.new(|$ev)
+ }
+}
+
+## Sending events to a room
+
+#| PUT - /_matrix/client/r0/rooms/{roomId}/send/{eventType}/{txnId}
+method send(Str $body!, Str :$type? = "m.text") {
+ $Matrix::Client::Common::TXN-ID++;
+ my $res = $.put(
+ "/send/m.room.message/{$Matrix::Client::Common::TXN-ID}",
+ msgtype => $type, body => $body
+ );
+
+ from-json($res.content)<event_id>
}
#| PUT - /_matrix/client/r0/rooms/{roomId}/state/{eventType}/{stateKey}
@@ -94,11 +142,49 @@ method send-state(Str:D $event-type, :$state-key = "", *%args --> Str) {
from-json($res.content)<event_id>
}
+# Room membership!
+
+## Joining rooms
+
+#| POST - /_matrix/client/r0/rooms/{roomId}/invite
+method invite(Str $user-id) {
+ $.post('/invite', :$user-id)
+}
+
+#| POST - /_matrix/client/r0/rooms/{roomId}/join
+method join {
+ $.post('/join')
+}
+
+## Leaving rooms
+
#| POST - /_matrix/client/r0/rooms/{roomId}/leave
-method leave() {
+method leave {
$.post('/leave')
}
+#| POST - /_matrix/client/r0/rooms/{roomId}/forget
+method forget {
+ $.post('/forget')
+}
+
+#| POST - /_matrix/client/r0/rooms/{roomId}/kick
+method kick(Str $user-id, Str $reason = "") {
+ $.post('/kick', :$user-id, :$reason)
+}
+
+## Banning users
+
+#| POST - /_matrix/client/r0/rooms/{roomId}/ban
+method ban(Str $user-id, $reason = "") {
+ $.post('/ban', :$user-id, :$reason)
+}
+
+#| POST - /_matrix/client/r0/rooms/{roomId}/unban
+method unban(Str $user-id) {
+ $.post('/unban', :$user-id)
+}
+
method Str(--> Str) {
"Room<id: {self.id}>"
}
diff --git a/lib/Matrix/Response.pm6 b/lib/Matrix/Response.pm6
index 268be84..a0b2896 100644
--- a/lib/Matrix/Response.pm6
+++ b/lib/Matrix/Response.pm6
@@ -23,6 +23,10 @@ class Matrix::Response::StateEvent is Matrix::Response::RoomEvent {
has $.state_key;
}
+class Matrix::Response::MemberEvent is Matrix::Response::StateEvent {
+ has $.type is required where 'm.room.member';
+}
+
class Matrix::Response::Timeline {
has Matrix::Response::Event @.events;
has Bool $limited;
@@ -54,6 +58,12 @@ sub gather-events($room-id, $from) {
}
}
+class Matrix::Response::Messages {
+ has $.start;
+ has $.end;
+ has Matrix::Response::RoomEvent @.messages;
+}
+
class Matrix::Response::Sync {
has Str $.next-batch;
has Matrix::Response::Event @.presence;
@@ -123,7 +133,6 @@ class Tag {
}
}
-
class Matrix::Response::Device {
has Str $.device-id;
has $.display-name;
@@ -137,3 +146,11 @@ class Matrix::Response::Device {
:last_seen_ts(:$!last-seen-ts)?
) { }
}
+
+class Matrix::Response::MediaStore::Config {
+ has Int $.upload-size;
+
+ method new(%config) {
+ self.bless(:upload-size(%config<m.upload.size> // Int));
+ }
+}