# CsBot3 - Matrix Client
- Added CsBot3::Matrix library in src/lib - Added dotenv support - Added login, room joining, and event listening functions
This commit is contained in:
parent
0e385f7bdb
commit
9837b3c5e8
6 changed files with 357 additions and 147 deletions
66
.gitignore
vendored
Normal file
66
.gitignore
vendored
Normal file
|
@ -0,0 +1,66 @@
|
|||
# Created by https://www.toptal.com/developers/gitignore/api/perl,visualstudiocode,dotenv
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=perl,visualstudiocode,dotenv
|
||||
|
||||
### dotenv ###
|
||||
.env
|
||||
|
||||
### Perl ###
|
||||
!Build/
|
||||
.last_cover_stats
|
||||
/META.yml
|
||||
/META.json
|
||||
/MYMETA.*
|
||||
*.o
|
||||
*.pm.tdy
|
||||
*.bs
|
||||
|
||||
# Devel::Cover
|
||||
cover_db/
|
||||
|
||||
# Devel::NYTProf
|
||||
nytprof.out
|
||||
|
||||
# Dist::Zilla
|
||||
/.build/
|
||||
|
||||
# Module::Build
|
||||
_build/
|
||||
Build
|
||||
Build.bat
|
||||
|
||||
# Module::Install
|
||||
inc/
|
||||
|
||||
# ExtUtils::MakeMaker
|
||||
/blib/
|
||||
/_eumm/
|
||||
/*.gz
|
||||
/Makefile
|
||||
/Makefile.old
|
||||
/MANIFEST.bak
|
||||
/pm_to_blib
|
||||
/*.zip
|
||||
|
||||
# Carton
|
||||
local/
|
||||
|
||||
### VisualStudioCode ###
|
||||
.vscode/*
|
||||
!.vscode/settings.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
!.vscode/extensions.json
|
||||
!.vscode/*.code-snippets
|
||||
|
||||
# Local History for Visual Studio Code
|
||||
.history/
|
||||
|
||||
# Built Visual Studio Code Extensions
|
||||
*.vsix
|
||||
|
||||
### VisualStudioCode Patch ###
|
||||
# Ignore all local history of files
|
||||
.history
|
||||
.ionide
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/perl,visualstudiocode,dotenv
|
15
config.json
15
config.json
|
@ -20,18 +20,5 @@
|
|||
"lastfmaliases": {
|
||||
"nicolapcweek94": "citizenwasp"
|
||||
},
|
||||
"modules": [
|
||||
"autorejoin",
|
||||
"trakt",
|
||||
"lastfm",
|
||||
"specials",
|
||||
"dieroll",
|
||||
"scp",
|
||||
"mtg",
|
||||
"emergency",
|
||||
"isup",
|
||||
"reddit",
|
||||
"niggaradio",
|
||||
"linktitles"
|
||||
]
|
||||
"modules": []
|
||||
}
|
||||
|
|
5
cpanfile
Normal file
5
cpanfile
Normal file
|
@ -0,0 +1,5 @@
|
|||
#cpanfile
|
||||
|
||||
requires 'Module::Reload';
|
||||
requires 'Env::Dot';
|
||||
requires 'JSON';
|
72
csbot3.pl
Normal file
72
csbot3.pl
Normal file
|
@ -0,0 +1,72 @@
|
|||
#/usr/bin/env perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use diagnostics;
|
||||
use JSON;
|
||||
use Module::Reload;
|
||||
use threads;
|
||||
use feature "say";
|
||||
use Cwd 'abs_path';
|
||||
use File::Basename;
|
||||
use ENV::Util;
|
||||
|
||||
BEGIN {
|
||||
ENV::Util::load_dotenv('.env');
|
||||
|
||||
my $script_dir = dirname(abs_path($0));
|
||||
push @INC, "$script_dir/src/lib";
|
||||
}
|
||||
|
||||
use CsBot3::Matrix;
|
||||
|
||||
# my $jsonconf = "";
|
||||
# open(my $config, "<", "config.json");
|
||||
# foreach (<$config>)
|
||||
# {
|
||||
# $jsonconf .= $_;
|
||||
# }
|
||||
# close $config;
|
||||
# $config = decode_json $jsonconf;
|
||||
# if ($@) {
|
||||
# die("Error parsing JSON: $@");
|
||||
# }
|
||||
#
|
||||
# my $modules = $config -> {"modules"};
|
||||
#
|
||||
# foreach (@$modules)
|
||||
# {
|
||||
# my $fullname = "csbot2::$_";
|
||||
# eval "use modules::$_";
|
||||
# die("Cannot load $_ : $@") if $@;
|
||||
# #say $_;
|
||||
# $fullname -> init();
|
||||
# }
|
||||
#
|
||||
# $|++; # enable autoflushing
|
||||
#
|
||||
# my $irc;
|
||||
# my $server = $config -> {"config"} -> {"server"};
|
||||
# my $port = $config -> {"config"} -> {"port"};
|
||||
# my $nick = $config -> {"config"} -> {"nick"};
|
||||
# my $channels = $config -> {"config"} -> {"channels"};
|
||||
# my $password = $config -> {"config"} -> {"password"};
|
||||
# my $masters = $config -> {"config"} -> {"masters"};
|
||||
# my $ignore = $config -> {"config"} -> {"ignore"};
|
||||
# my $version = "0.2.6 now with slightly better module loading!";
|
||||
my $matrix = CsBot3::Matrix::new($ENV{MATRIX_SERVER});
|
||||
|
||||
my %credentials = (
|
||||
type => "m.login.password",
|
||||
user => $ENV{MATRIX_USER},
|
||||
password => $ENV{MATRIX_PASSWORD},
|
||||
);
|
||||
|
||||
my $room = $ENV{MATRIX_DEFAULT_ROOM};
|
||||
|
||||
my $login = CsBot3::Matrix::login(\%credentials);
|
||||
|
||||
if($login) {
|
||||
CsBot3::Matrix::join_room($room);
|
||||
CsBot3::Matrix->read_events();
|
||||
}
|
133
src/csbot2.pl
133
src/csbot2.pl
|
@ -1,133 +0,0 @@
|
|||
#/usr/bin/env perl
|
||||
use strict;
|
||||
use warnings;
|
||||
use diagnostics;
|
||||
use JSON;
|
||||
use Module::Reload;
|
||||
use threads;
|
||||
use feature "say";
|
||||
|
||||
my $jsonconf = "";
|
||||
open(my $config, "<", "config.json");
|
||||
foreach (<$config>)
|
||||
{
|
||||
$jsonconf .= $_;
|
||||
}
|
||||
close $config;
|
||||
$config = decode_json $jsonconf;
|
||||
|
||||
my $modules = $config -> {"modules"};
|
||||
|
||||
foreach (@$modules)
|
||||
{
|
||||
my $fullname = "csbot2::$_";
|
||||
eval "use modules::$_";
|
||||
die("Cannot load $_ : $@") if $@;
|
||||
#say $_;
|
||||
$fullname -> init();
|
||||
}
|
||||
|
||||
$|++; # enable autoflushing
|
||||
|
||||
my $irc;
|
||||
my $server = $config -> {"config"} -> {"server"};
|
||||
my $port = $config -> {"config"} -> {"port"};
|
||||
my $nick = $config -> {"config"} -> {"nick"};
|
||||
my $channels = $config -> {"config"} -> {"channels"};
|
||||
my $password = $config -> {"config"} -> {"password"};
|
||||
my $masters = $config -> {"config"} -> {"masters"};
|
||||
my $ignore = $config -> {"config"} -> {"ignore"};
|
||||
my $version = "0.2.6 now with slightly better module loading!";
|
||||
|
||||
if ($config -> {"config"} -> {"ssl"} == 1)
|
||||
{
|
||||
eval "use IO::Socket::SSL";
|
||||
$irc = IO::Socket::SSL -> new (
|
||||
PeerAddr => $server,
|
||||
PeerPort => $port,
|
||||
Proto => "tcp"
|
||||
) or die "Couldn't connect to IRC: $!";
|
||||
}
|
||||
else
|
||||
{
|
||||
eval "use IO::Socket::INET";
|
||||
$irc = IO::Socket::INET -> new (
|
||||
PeerAddr => $server,
|
||||
PeerPort => $port,
|
||||
Proto => "tcp"
|
||||
) or die "Couldn't connect to IRC: $!";
|
||||
}
|
||||
|
||||
my ($nick_s, $user_s, $host, $chan) = ("", "", "", "");
|
||||
|
||||
# USER non è nick!!
|
||||
say $irc "USER ", $nick, " 0 * :CounterStrikeBot strikes again";
|
||||
say $irc "NICK ", $nick;
|
||||
|
||||
while (<$irc>)
|
||||
{
|
||||
print;
|
||||
($nick_s, $user_s, $host, $chan) = ($1, $2, $3, $4) if /^:([^\s]+)!~?([^\s]+)@([^\s]+) PRIVMSG ([^\s]+)/;
|
||||
|
||||
say $irc "QUIT :bb madafackas" if $nick_s ~~ $masters and /^[^\s]+ PRIVMSG ${chan} :gtfo.*\b${nick}\b/i;
|
||||
|
||||
say $irc "PRIVMSG $chan :$version" if /^:(.+?)!.+?@.+? PRIVMSG ${chan} :.*\b?${nick} version.*$/i;
|
||||
|
||||
say $irc "PONG :", $1 if /^PING :(.+)$/i;
|
||||
|
||||
next if $nick_s ~~ $ignore;
|
||||
|
||||
if (/^:[^\s]+ (?:422|376)/) {
|
||||
say $irc "PRIVMSG NickServ :identify ", $password;
|
||||
foreach my $ch (@$channels)
|
||||
{
|
||||
say $irc "JOIN ", $ch;
|
||||
}
|
||||
}
|
||||
|
||||
if (/^:(.+?)!.+?@.+? PRIVMSG ${chan} :moduleload (\w+?)\s+?$/i)
|
||||
{
|
||||
if ($nick_s ~~ $masters and not $2 ~~ $modules)
|
||||
{
|
||||
my $fullname = "csbot2::$2";
|
||||
eval "use modules::$2; $fullname -> init()";
|
||||
|
||||
if ($@)
|
||||
{
|
||||
say $irc "PRIVMSG $chan :Cannot load $2 : $@";
|
||||
}
|
||||
else
|
||||
{
|
||||
push(@$modules, $2);
|
||||
say $irc "PRIVMSG $chan :Module $2 successfully loaded";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
say $irc "PRIVMSG $chan :You are not authorized to do that // The module is already loaded";
|
||||
}
|
||||
}
|
||||
|
||||
if (/^:(.+?)!.+?@.+? PRIVMSG ${chan} :moduleunload (\w+?)\s+?$/i)
|
||||
{
|
||||
if ($nick_s ~~ $masters and $2 ~~ $modules)
|
||||
{
|
||||
my $fullname = "csbot2::$2";
|
||||
eval "no modules::$2; Module::Reload -> check;";
|
||||
die("Cannot unload $2 : $@") if $@;
|
||||
@$modules = grep {$_ !~ $2} @$modules;
|
||||
say $irc "PRIVMSG $chan :Module $2 successfully unloaded";
|
||||
}
|
||||
}
|
||||
|
||||
say $irc "PRIVMSG ${chan} :Loaded modules: " . join(", ", @$modules) if /^:(.+?)!.+?@.+? PRIVMSG ${chan} :modulelist/i;
|
||||
|
||||
foreach my $name (@$modules)
|
||||
{
|
||||
my $mod = "csbot2::$name";
|
||||
#threads->create (sub { $mod->parse ($_, $irc, $config, $chan, $nick); })->detach;
|
||||
$mod->parse ($_, $irc, $config, $chan, $nick);
|
||||
}
|
||||
|
||||
($nick_s, $user_s, $host) = ("", "", "");
|
||||
}
|
213
src/lib/CsBot3/Matrix.pm
Normal file
213
src/lib/CsBot3/Matrix.pm
Normal file
|
@ -0,0 +1,213 @@
|
|||
package CsBot3::Matrix;
|
||||
|
||||
use JSON qw(encode_json decode_json);
|
||||
#use JSON::MaybeXS qw(encode_json decode_json);
|
||||
use HTTP::Request;
|
||||
use HTTP::Headers;
|
||||
use LWP::UserAgent;
|
||||
use URI;
|
||||
|
||||
our $user = "";
|
||||
our $tnx_id = 0;
|
||||
our $server;
|
||||
our $access_token = "";
|
||||
our %protocols_list = (
|
||||
'http' => 'http://',
|
||||
'https' => 'https://'
|
||||
);
|
||||
our $protocol = 'https';
|
||||
|
||||
our %routes = (
|
||||
login => '/_matrix/client/r0/login',
|
||||
join_room => '/_matrix/client/r0/join',
|
||||
sync => '/_matrix/client/r0/sync',
|
||||
room_send_message => '/_matrix/client/r0/rooms'
|
||||
);
|
||||
|
||||
our $request_headers = ['Content-Type' => 'application/json; charset=UTF-8'];
|
||||
|
||||
our $lwp = LWP::UserAgent->new();
|
||||
$lwp->agent('CsMatrix');
|
||||
|
||||
our @rooms = ();
|
||||
|
||||
sub new {
|
||||
my ($server) = @_;
|
||||
|
||||
$CsBot3::Matrix::server = $server;
|
||||
}
|
||||
|
||||
sub login {
|
||||
my ($credentials) = @_;
|
||||
|
||||
$CsBot3::Matrix::user = $credentials->{user};
|
||||
|
||||
my $request_url = get_request_url('login');
|
||||
|
||||
my $body = encode_json($credentials);
|
||||
|
||||
my $login_request = HTTP::Request->new(
|
||||
'POST',
|
||||
$request_url,
|
||||
$CsBot3::Matrix::request_headers,
|
||||
$body
|
||||
) or undef;
|
||||
|
||||
my $login_response = $CsBot3::Matrix::lwp->request($login_request) or undef;
|
||||
|
||||
if(!defined $login_response) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$CsBot3::Matrix::access_token = decode_json($login_response->{_content})->{access_token};
|
||||
|
||||
push(@$CsBot3::Matrix::request_headers, 'Authorization', "Bearer $CsBot3::Matrix::access_token");
|
||||
|
||||
print "[OK] - Login as $CsBot3::Matrix::user\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub join_room {
|
||||
my ($room) = @_;
|
||||
|
||||
|
||||
my $request_url = get_request_url('join_room');
|
||||
$request_url .= "/$room";
|
||||
$request_url .= "?access_token=$CsBot3::Matrix::access_token";
|
||||
|
||||
my $room_join_request = HTTP::Request->new(
|
||||
'POST',
|
||||
$request_url,
|
||||
$CsBot3::Matrix::request_headers,
|
||||
encode_json({})
|
||||
) or undef;
|
||||
my $room_join_response = $CsBot3::Matrix::lwp->request($room_join_request) or undef;
|
||||
|
||||
if(!defined $room_join_response) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
push(@CsBot3::Matrix::rooms, $room);
|
||||
|
||||
print "[OK] - Join room $room\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub read_events {
|
||||
my ($channel) = @_;
|
||||
|
||||
my $request_url = get_request_url('sync');
|
||||
|
||||
my $initial_sync_request = HTTP::Request->new(
|
||||
'GET',
|
||||
$request_url,
|
||||
$CsBot3::Matrix::request_headers,
|
||||
encode_json({})
|
||||
) or undef;
|
||||
my $initial_sync_response = $CsBot3::Matrix::lwp->request($initial_sync_request) or undef;
|
||||
|
||||
if(!defined $initial_sync_response) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
my $json = JSON->new->utf8->allow_nonref->allow_blessed->convert_blessed->pretty(1);
|
||||
my $content = decode_json($initial_sync_response->{_content})->{next_batch};
|
||||
|
||||
long_poll_event(next_batch);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub get_request_url {
|
||||
my ($request_type) = @_;
|
||||
|
||||
my $proto = $protocols_list{$CsBot3::Matrix::protocol};
|
||||
my $route = $CsBot3::Matrix::routes{$request_type};
|
||||
|
||||
if(defined $routes{$request_type}) {
|
||||
return "$proto$server$route";
|
||||
}
|
||||
|
||||
return undef;
|
||||
}
|
||||
|
||||
sub long_poll_event {
|
||||
my ($since) = @_;
|
||||
my $timeout = 300;
|
||||
my $request_url;
|
||||
|
||||
while (1) {
|
||||
print "[SYNC] - Events\n";
|
||||
|
||||
$request_url = get_request_url('sync');
|
||||
$request_url .= "?since=$since&timeout=$timeout";
|
||||
|
||||
$CsBot3::Matrix::lwp->timeout($timeout);
|
||||
|
||||
my $initial_sync_request = HTTP::Request->new(
|
||||
'GET',
|
||||
$request_url,
|
||||
$CsBot3::Matrix::request_headers,
|
||||
encode_json({})
|
||||
) or undef;
|
||||
|
||||
my $initial_sync_response = $CsBot3::Matrix::lwp->request($initial_sync_request) or undef;
|
||||
|
||||
if ($initial_sync_response->is_success && $initial_sync_response->{_content}) {
|
||||
my $json_response = decode_json($initial_sync_response->{_content});
|
||||
my $next_batch = $json_response->{next_batch};
|
||||
|
||||
foreach my $room (@CsBot3::Matrix::rooms) {
|
||||
if(defined $json_response->{rooms}->{join}->{$room}->{timeline}->{events}) {
|
||||
$events = $json_response->{rooms}->{join}->{$room}->{timeline}->{events};
|
||||
foreach my $event (@$events) {
|
||||
|
||||
if(
|
||||
$event->{type} eq "m.room.message" &&
|
||||
time() - $event->{origin_server_ts} <= 1000 &&
|
||||
defined $CsBot3::Matrix::user &&
|
||||
$event->{sender} ne $CsBot3::Matrix::user
|
||||
) {
|
||||
send_message($room);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$since = $next_batch;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub send_message {
|
||||
my ($room) = @_;
|
||||
|
||||
|
||||
my $request_url = get_request_url('room_send_message');
|
||||
$request_url .= "/$room/send/m.room.message/$CsBot3::Matrix::tnx_id";
|
||||
|
||||
$CsBot3::Matrix::tnx_id += 1;
|
||||
|
||||
my $body = {
|
||||
"msgtype" => "m.text",
|
||||
"body" => "Message received."
|
||||
};
|
||||
|
||||
my $room_send_message_request = HTTP::Request->new(
|
||||
'PUT',
|
||||
$request_url,
|
||||
$CsBot3::Matrix::request_headers,
|
||||
encode_json($body)
|
||||
) or undef;
|
||||
|
||||
my $room_send_message_response = $CsBot3::Matrix::lwp->request($room_send_message_request) or undef;
|
||||
|
||||
if(!defined $room_send_message_response) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
Loading…
Add table
Reference in a new issue