aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Matrix/Client.pm6138
-rw-r--r--lib/Matrix/Client/Common.pm63
-rw-r--r--lib/Matrix/Client/Requester.pm652
-rw-r--r--lib/Matrix/Client/Room.pm646
4 files changed, 239 insertions, 0 deletions
diff --git a/lib/Matrix/Client.pm6 b/lib/Matrix/Client.pm6
new file mode 100644
index 0000000..6849fe4
--- /dev/null
+++ b/lib/Matrix/Client.pm6
@@ -0,0 +1,138 @@
+use HTTP::Request::Common;
+use URI::Encode;
+use JSON::Tiny;
+use Matrix::Client::Common;
+use Matrix::Client::Room;
+use Matrix::Client::Requester;
+
+unit class Matrix::Client does Matrix::Client::Requester;
+
+has Str $!user-id;
+has Str $!device-id;
+has Str $.state-file = 'state';
+has @!rooms;
+has @!users;
+
+method user-id() {
+ $!user-id
+}
+
+method device-id() {
+ $!device-id
+}
+
+method login(Str $username, Str $pass) returns Bool {
+ if $.state-file.IO.e {
+ my $data = from-json(slurp $.state-file);
+ $!access-token = $data<access_token>;
+ $!user-id = $data<user_id>;
+ $!device-id = $data<device_id>;
+ $Matrix::Client::Common::TXN-ID = $data<txn_id> // 0;
+ return True
+ }
+
+ # Handle POST
+ my $data = to-json {
+ type => "m.login.password",
+ user => $username,
+ password => $pass
+ };
+
+ my $res = $.post("/login", $data);
+ if $res.is-success {
+ spurt $.state-file, $res.content;
+ my $data = from-json($res.content);
+ $!access-token = $data<access_token>;
+ $!user-id = $data<user_id>;
+ $!device-id = $data<device_id>;
+ True
+ } else {
+ False
+ }
+}
+
+method finish() {
+ my %data =
+ access_token => $!access-token,
+ user_id => $!user-id,
+ device_id => $!device-id,
+ txn_id => $Matrix::Client::Common::TXN-ID;
+
+ spurt $.state-file, to-json(%data);
+}
+
+method logout() {
+ unlink $.state-file;
+ $.post("/logout")
+}
+
+method register($username, $password, Bool :$bind-email? = False) {
+ my $res = $.post("/register",
+ username => $username, password => $password,
+ bind_email => $bind-email,
+ auth => {
+ type => "m.login.dummy"
+ });
+ if $res.is-success {
+ my $data = from-json $res.content;
+ $!access-token = $data<access_token>;
+ $.user-id = $data<user_id>;
+ } else {
+ die "Error with the homeserver: " ~ $res.content;
+ }
+}
+
+method check-res($res) {
+ if $res.is-success {
+ True
+ } else {
+ warn $res.status-line;
+ warn $res.content;
+ False
+ }
+}
+
+multi method sync() {
+ my $res = $.get("/sync",
+ timeout => 30000
+ );
+
+ $.check-res($res);
+ $res
+}
+
+multi method sync(Str :$sync-filter, Str :$since = "") {
+ my $res = $.get("/sync",
+ timeout => 30000,
+ filter => $sync-filter,
+ since => $since
+ );
+
+ $.check-res($res);
+ $res
+}
+
+multi method sync(:$sync-filter is copy, :$since = "") {
+ $.sync(sync-filter => to-json($sync-filter), since => $since)
+}
+
+method join-room($room-id!) {
+ $.post("/join/" ~ $room-id)
+}
+
+method rooms() {
+ my $res = $.get("/sync", timeout => "30000");
+
+ return () unless $res.is-success;
+ my $data = from-json($res.content);
+ for $data<rooms><join>.kv -> $id, $json {
+ @!rooms.push(Matrix::Client::Room.new(id => $id, json => $json, home-server => $!home-server));
+ }
+
+ @!rooms
+}
+
+method send(Str $room-id, Str $body, :$type? = "m.text") {
+ $Matrix::Client::Common::TXN-ID++;
+ $.put("/rooms/$room-id/send/m.room.message/{$Matrix::Client::Common::TXN-ID}", msgtype => $type, body => $body)
+}
diff --git a/lib/Matrix/Client/Common.pm6 b/lib/Matrix/Client/Common.pm6
new file mode 100644
index 0000000..670f8e3
--- /dev/null
+++ b/lib/Matrix/Client/Common.pm6
@@ -0,0 +1,3 @@
+unit module Matrix::Client::Common;
+
+our $TXN-ID = 0;
diff --git a/lib/Matrix/Client/Requester.pm6 b/lib/Matrix/Client/Requester.pm6
new file mode 100644
index 0000000..c2ba865
--- /dev/null
+++ b/lib/Matrix/Client/Requester.pm6
@@ -0,0 +1,52 @@
+use HTTP::UserAgent;
+use HTTP::Request::Common;
+use URI::Encode;
+use JSON::Tiny;
+
+unit role Matrix::Client::Requester;
+
+has $!ua = HTTP::UserAgent.new;
+has $.home-server is required;
+has $!client-endpoint = "/_matrix/client/r0";
+has $!url-prefix = "";
+has $!access-token = "";
+has $!sync-since = "";
+
+method get(Str $path, *%data) {
+ my $q = "$path?access_token=$!access-token";
+ for %data.kv -> $k,$v {
+ $q ~= "&$k=$v" unless $v eq "";
+ }
+ my $uri = uri_encode($.base-url ~ $q);
+
+ $!ua.history = [];
+ $!ua.get($uri)
+}
+
+method base-url(--> Str) {
+ "$.home-server$!client-endpoint$!url-prefix"
+}
+
+multi method post(Str $path, Str $json) {
+ my $req = HTTP::Request.new(POST => $.base-url() ~ $path ~ "?access_token=$!access-token",
+ Content-Type => 'application/json');
+ $req.add-content($json);
+ $!ua.history = [];
+ $!ua.request($req)
+}
+
+multi method post(Str $path, *%params) {
+ self.post($path, to-json(%params))
+}
+
+multi method put(Str $path,Str $json) {
+ my $req = HTTP::Request.new(PUT => $.base-url() ~ $path ~ "?access_token=$!access-token",
+ Content-Type => 'application/json');
+ $req.add-content($json);
+ $!ua.history = [];
+ $!ua.request($req)
+}
+
+multi method put(Str $path, *%params) {
+ self.put($path, to-json(%params))
+}
diff --git a/lib/Matrix/Client/Room.pm6 b/lib/Matrix/Client/Room.pm6
new file mode 100644
index 0000000..5601f33
--- /dev/null
+++ b/lib/Matrix/Client/Room.pm6
@@ -0,0 +1,46 @@
+use JSON::Tiny;
+use Matrix::Client::Common;
+use Matrix::Client::Requester;
+
+unit class Matrix::Client::Room does Matrix::Client::Requester;
+
+has $.name is rw;
+has $.id is rw;
+has $!prev-batch;
+
+submethod BUILD(Str :$id!, :$json, :$home-server!) {
+ $!home-server = $home-server;
+ $!id = $id;
+ $!url-prefix = "/rooms/$!id";
+ $!prev-batch = $json<timeline><prev_batch>;
+
+ if so $json {
+ my @events = $json<state><events>.clone;
+ for @events -> $ev {
+ if $ev<type> eq "m.room.name" {
+ $!name = $ev<content><name>;
+ }
+ }
+ }
+
+ # FIXME: Should be a 1:1 conversation
+ unless $!name {
+ $!name = "Unknown";
+ }
+}
+
+method messages() {
+ my $res = $.get("/messages");
+ my $data = from-json($res.content);
+
+ return $data<chunk>.clone;
+}
+
+method send($room-id, Str $body!, Str :$type? = "m.text") {
+ $Matrix::Client::Common::TXN-ID++;
+ $.put("/send/m.room.message/{$Matrix::Client::Common::TXN-ID}", msgtype => $type, body => $body)
+}
+
+method gist(--> Str) {
+ "Room<name: $.name, id: $.id>"
+}