Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Matias Linares
committed
Apr 4, 2017
0 parents
commit 9c439e6
Showing
10 changed files
with
383 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
state | ||
file.json | ||
**/*/.precomp |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
{ | ||
"perl" : "6.c", | ||
"name" : "Matrix::Client", | ||
"version" : "0.1.0", | ||
"description" : "Simple matrix.org client", | ||
"tags" : [ "Net", "Matrix" ], | ||
"depends" : [ | ||
"JSON::Tiny", | ||
"HTTP::UserAgent", | ||
"URI::Encode" | ||
], | ||
"test-depends" : [ | ||
"Test", | ||
"Test::META" | ||
], | ||
"provides" : { | ||
"Matrix::Client" : "lib/Matrix/Client.pm6", | ||
"Matrix::Client::Room" : "lib/Matrix/Client/Room.pm6", | ||
"Matrix::Client::Requester" : "lib/Matrix/Client/Requester.pm6", | ||
"Matrix::Client::Common" : "lib/Matrix/Client/Common.pm6" | ||
}, | ||
"authors" : ["Matias Linares"], | ||
"support" : {"source" : ""} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
#!/usr/bin/env perl6 | ||
use v6; | ||
use lib "lib"; | ||
use JSON::Tiny; | ||
use Matrix::Client; | ||
|
||
class Bot { | ||
has $!name = "deprecated"; | ||
has $!username is required; | ||
has Bool $!register = False; | ||
has @!room-ids; | ||
|
||
has $!on-event; | ||
|
||
has Matrix::Client $!client; | ||
|
||
submethod BUILD(:$username!, :$password!, :$home-server!, :@room-ids!, :$on-event!) { | ||
$!client = Matrix::Client.new(:home-server($home-server)); | ||
$!username = $username; | ||
@!room-ids = @room-ids; | ||
$!on-event = $on-event; | ||
|
||
$!client.login($!username, $password); | ||
} | ||
|
||
method join-rooms() { | ||
@!room-ids.map: { $!client.join-room($_) } | ||
} | ||
|
||
method shutdown() { | ||
$!client.finish; | ||
} | ||
|
||
method listen() { | ||
say "Listening"; | ||
my $since = ""; | ||
|
||
loop { | ||
my $sync = { room => timeline => limit => 1 }; | ||
my $data = from-json($!client.sync(sync-filter => $sync, since => $since).content); | ||
$since = $data<next_batch>; | ||
|
||
for $data<rooms><join>.kv -> $room-id, $d { | ||
for @($d<timeline><events>) -> $ev { | ||
if $ev<type> eq "m.room.message" { | ||
if $ev<content><body>.match($!name) { | ||
my $bot-msg = $!on-event($ev); | ||
if so $bot-msg { | ||
say "Sending message $bot-msg"; | ||
my $res = $!client.send($room-id, ~$bot-msg); | ||
if $res.is-success { | ||
say $res.content; | ||
} else { | ||
warn $res.content; | ||
die $res.status-line; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
sleep(10); | ||
} | ||
} | ||
} | ||
|
||
sub MAIN(Str:D $username, Str:D $password, :$home-server = "https://matrix.deprecated.org") { | ||
my @rooms = "!bpHGYOiCGlvCZarfMH:matrix.deprecated.org"; | ||
my $bot = Bot.new: | ||
username => $username, | ||
password => $password, | ||
home-server => $home-server, | ||
room-ids => @rooms, | ||
on-event => -> $ev { | ||
given $ev<content><body> { | ||
when /"say hi"/ { | ||
say "Someone is saying hi!"; | ||
"Hello @ {DateTime.now}" | ||
} | ||
default { say "Dunno what's telling me"; Str } | ||
} | ||
}; | ||
|
||
signal(SIGINT).tap({ | ||
$bot.shutdown; | ||
exit 0; | ||
}); | ||
|
||
my $ress = $bot.join-rooms; | ||
for @($ress) -> $res { | ||
if !$res.is-success { | ||
warn $res.status-line; | ||
warn $res.content; | ||
} | ||
} | ||
|
||
$bot.listen; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
use Matrix::Client; | ||
|
||
my $c = Matrix::Client.new: :home-server<https://matrix.deprecated.org>; | ||
$c.login: @*ARGS[0], @*ARGS[1]; | ||
|
||
say $c.rooms; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
unit module Matrix::Client::Common; | ||
|
||
our $TXN-ID = 0; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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>" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
use lib 'lib'; | ||
use Test; | ||
use Test::META; | ||
|
||
meta-ok; | ||
done-testing; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
use lib 'lib'; | ||
use Test; | ||
|
||
use-ok 'Matrix::Client'; | ||
use-ok 'Matrix::Client::Room'; | ||
use-ok 'Matrix::Client::Requester'; | ||
done-testing; |