Skip to content

Instantly share code, notes, and snippets.

@Likk
Last active March 24, 2017 12:09
Show Gist options
  • Save Likk/24c7f444e552503ae1ee to your computer and use it in GitHub Desktop.
Save Likk/24c7f444e552503ae1ee to your computer and use it in GitHub Desktop.
コマンドラインからslackチャット
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Carp;
use Config::Pit;
use DateTime;
use Encode;
use Term::ANSIColor;
use Term::ReadLine;
use Try::Tiny;
use WebService::Slack::WebApi;
local $| = 1;
our $TOKEN = {};
our $USERS_MASTER = {};
our $GROUPS_MASTER = {};
our $CHANNEL_MASTER = {};
our $TL = [];
our $LAST_SET = time - 3600;
our $KEYWORDS = [qw/!group all/];
our $SAVE_FILE_PATH = ''; #別途ファイル保存したいケース
{
local $ENV{EDITOR} = 'vim';
my $pit = pit_get('api.slack.com',
require => {
token => 'your token',
},
);
$TOKEN = $pit->{token};
}
my $slack = WebService::Slack::WebApi->new(token => $TOKEN);
main();
sub main {
request_users();
timeline_process();
if(my $pid =fork()){
post_process();
wait;
}
elsif(defined $pid){
while(1){
timeline_process();
sleep 30;
}
}
else{
die 'cant fork';
}
}
sub post_process {
my $term = Term::ReadLine->new('slack');
my $channel = undef;
my $channel_regex = qr/\A#([-A-Za-z0-9]+)(?:\s)?/;
while (defined (my $in = $term->readline())) {
try {
my $result = $in;
$term->addhistory($in);
if($result =~ m{$channel_regex}){
my $channel_name = $1;
for my $id (keys %$CHANNEL_MASTER){
if($CHANNEL_MASTER->{$id} and
$CHANNEL_MASTER->{$id}->{name} eq $channel_name){
$channel = $id;
last;
}
}
for my $id (keys %$GROUPS_MASTER){
if($GROUPS_MASTER->{$id} and
$GROUPS_MASTER->{$id}->{name} eq $channel_name){
$channel = $id;
last;
}
}
}
die 'cant find channel' unless $channel;
$result =~ s{$channel_regex}{};
my $res = request_channel_timelines(
sub {
$slack->chat->post_message(
as_user => 1,
channel => $channel,
text => $result,
);
}
);
}
catch {
my $e = $_;
warn $e;
};
}
}
sub timeline_process {
clear_tl();
request_channel_timelines();
request_group_timelines();
display_tl();
}
sub display_tl {
for my $row (sort { $a->{epoch} <=> $b->{epoch} } @$TL){
my $dt = DateTime->from_epoch(epoch => $row->{epoch}, time_zone => 'local' );
my $ymdhms = $dt->ymd . ' ' . $dt->hms;
my $message = $row->{message};
for my $keyword (@$KEYWORDS){
if($message =~ m{$keyword}){
$message =~ s{$keyword}{@{[ color('red') ]}$keyword@{[ color('reset') ]}};
print "\a";
}
}
my $line = sprintf("[%s] <%s\@%s> :%-10s",
color('yellow') . $ymdhms . color('reset'),
color('cyan') . $row->{user} . color('reset'),
color('green') . $row->{channel} . color('reset'),
color('bright_white') . Encode::encode_utf8($message) . color('reset'),
);
print $line;
print "\n";
if($SAVE_FILE_PATH){
open(my $fh, '>>', $SAVE_FILE_PATH);
print $fh $line;
print $fh "\n";
close $fh;
}
}
}
sub reqest_with_retry {
my $code = shift;
my $caller = [ caller(1) ];
my $retry_count = 10;
my $res;
my $e;
for my $count_num (1..$retry_count){
$res =
try {
return $code->();
}
catch {
$e .= $_;
$e .= $caller->[1] . ':' . $caller->[2];
$e .= "\n";
if($count_num == 1 ){
print 'wait.';
}
else {
print '..';
}
return;
};
last if $res;
};
if($res){
print "\r" if $e;
return $res;
}
die $e;
}
sub user_id2name {
my $string = shift;
my $ids = [ split /\|/, $string ];
if(scalar @$ids >= 2){
return $ids->[-1];
}
my $id = $ids->[0];
unless($USERS_MASTER->{$id}){
#request_users();
}
my $user = $USERS_MASTER->{$id};
return $user ? $user->{name} : $id;
}
sub request_users {
my $user_list = reqest_with_retry(
sub { $slack->users->list->{members} }
);
for my $user (@$user_list){
unless ($USERS_MASTER->{$user->{id}}){
$USERS_MASTER->{$user->{id}} = {
name => $user->{name},
};
}
}
}
sub request_channel_timelines {
my $join_channel_list = reqest_with_retry(
sub { $slack->channels->list->{channels} }
);
for my $channel (@{ $join_channel_list }){
my $id = $channel->{id};
unless($CHANNEL_MASTER->{$id}){
$CHANNEL_MASTER->{$id} = {
name => $channel->{name},
last_set => $LAST_SET,
};
}
my $channel_timeline = reqest_with_retry(
sub { $slack->channels->history({ channel => $id, count=> 10}) }
)->{messages};
for my $row (reverse @$channel_timeline){
if($row->{ts} > $CHANNEL_MASTER->{$id}->{last_set}){
my $user;
if($row->{user}){
$user = user_id2name($row->{user});
}
else {
$user = 'bot';
}
my $text = $row->{text};
$text =~ s/(?:<\@([-A-Za-z0-9\|]{6,})>)/\@@{[ user_id2name( $1 ) ]}/g;
$text =~ s/\n/\\n/g;
push_tl({
epoch => $row->{ts},
channel => $channel->{name},
user => $user,
message => $text,
});
$CHANNEL_MASTER->{$id}->{last_set} = $row->{ts};
}
}
}
}
sub request_group_timelines {
my $join_group_list = reqest_with_retry(
sub { $slack->groups->list->{groups} }
);
for my $group (@{ $join_group_list }){
my $id = $group->{id};
unless($GROUPS_MASTER->{$id}){
$GROUPS_MASTER->{$id} = {
name => $group->{name},
last_set => $LAST_SET,
};
}
my $group_timeline = reqest_with_retry(
sub { $slack->groups->history({ channel => $id, count=> 10}) }
)->{messages};
for my $row (reverse @$group_timeline){
if($row->{ts} > $GROUPS_MASTER->{$id}->{last_set}){
my $user;
if($row->{user}){
$user = user_id2name($row->{user});
}
else {
$user = 'bot';
}
my $text = $row->{text};
$text =~ s/(?:<\@([-A-Za-z0-9\|]{6,})>)/\@@{[ user_id2name( $1 ) ]}/g;
$text =~ s/\n/\\n/g;
$GROUPS_MASTER->{$id}->{last_set} = $row->{ts};
push_tl({
epoch => $row->{ts},
channel => $group->{name},
user => $user,
message => $text,
});
}
}
}
}
sub push_tl { push @$TL, shift }
sub clear_tl { $TL = [] }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment