Last active
March 24, 2017 12:09
-
-
Save Likk/24c7f444e552503ae1ee to your computer and use it in GitHub Desktop.
コマンドラインからslackチャット
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
#!/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