From 1c341aaae67243ee9b5eb2bbfa96ec675a8b0874 Mon Sep 17 00:00:00 2001 From: Lukas Erlacher Date: Fri, 21 Aug 2026 12:10:38 +1000 Subject: [PATCH 1/7] wip --- lib/Synergy/External/Slack.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Synergy/External/Slack.pm b/lib/Synergy/External/Slack.pm index 8cb55d60..0fe103c5 100644 --- a/lib/Synergy/External/Slack.pm +++ b/lib/Synergy/External/Slack.pm @@ -134,7 +134,7 @@ async sub connect ($self) { until ($json) { my $res = await $self->hub->http_client->GET( - "https://slack.com/api/rtm.connect?token=" . $self->api_key + "https://slack.com/api/app.connections.open", { headers => { Authorization => "Bearer " . $self->api_key}} ); if ($res->code == 429) { From f4080f7403ee81f27a82cea2f2694a8cc37d3b90 Mon Sep 17 00:00:00 2001 From: Lukas Erlacher Date: Mon, 24 Aug 2026 13:36:43 +1000 Subject: [PATCH 2/7] wip wip wip --- lib/Synergy/Channel/Slack.pm | 7 +++++++ lib/Synergy/External/Slack.pm | 36 ++++++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/lib/Synergy/Channel/Slack.pm b/lib/Synergy/Channel/Slack.pm index 6df62651..4fffc415 100644 --- a/lib/Synergy/Channel/Slack.pm +++ b/lib/Synergy/Channel/Slack.pm @@ -18,6 +18,12 @@ my $JSON = JSON::MaybeXS->new->canonical; with 'Synergy::Role::Channel', 'Synergy::Role::ProvidesUserStatus'; +has app_key => ( + is => 'ro', + isa => 'Str', + required => 1, +); + has api_key => ( is => 'ro', isa => 'Str', @@ -37,6 +43,7 @@ has slack => ( default => sub ($self) { my $slack = Synergy::External::Slack->new( loop => $self->loop, + app_key => $self->app_key, api_key => $self->api_key, name => '_external_slack', privileged_api_key => $self->privileged_api_key, diff --git a/lib/Synergy/External/Slack.pm b/lib/Synergy/External/Slack.pm index 0fe103c5..172038fa 100644 --- a/lib/Synergy/External/Slack.pm +++ b/lib/Synergy/External/Slack.pm @@ -18,6 +18,8 @@ use Synergy::Logger '$Logger'; with 'Synergy::Role::HubComponent'; +has app_key => ( is => 'ro', required => 1 ); + has api_key => ( is => 'ro', required => 1 ); has privileged_api_key => ( @@ -132,9 +134,29 @@ async sub connect ($self) { my $json; + my $user_info_res = await $self->hub->http_client->GET( + "https://slack.com/api/auth.test", content_type => 'application/x-www-form-urlencoded', headers => { Authorization => "Bearer " . $self->api_key} + ); + $json = decode_json($user_info_res->content); + die "Could not connect to Slack RTM: $json->{error}" + unless $json->{ok}; + + $Logger->log($user_info_res->content); + + my $our_name = $json->{user}; + $our_name = 'synergy' if $our_name eq 'synergee'; + + $Logger->log("we have a name: $our_name"); + + $self->_set_own_name($our_name); + $self->_set_own_id($json->{user_id}); + $self->_set_team_data({team => $json->{team}, team_id => $json->{team_id}}); + + $json = undef; + until ($json) { - my $res = await $self->hub->http_client->GET( - "https://slack.com/api/app.connections.open", { headers => { Authorization => "Bearer " . $self->api_key}} + my $res = await $self->hub->http_client->POST( + "https://slack.com/api/apps.connections.open", '', content_type => 'application/x-www-form-urlencoded', headers => { Authorization => "Bearer " . $self->app_key} ); if ($res->code == 429) { @@ -145,7 +167,9 @@ async sub connect ($self) { $json = decode_json($res->content); - die "Could not connect to Slack RTM: $json->{error}" + my $reqh = $res->request->header('Authorization'); + + die "Could not connect to Slack RTM: $json->{error} // $reqh" unless $json->{ok}; } @@ -156,12 +180,6 @@ async sub connect ($self) { # do. I *think* that reinstalling the app to our workspace would fix this, # but I'm not entirely sure and I don't want to make everyone open yet # another DM with synergy, so here we are. -- michael, 2019-06-03 - my $our_name = $json->{self}->{name}; - $our_name = 'synergy' if $our_name eq 'synergee'; - - $self->_set_own_name($our_name); - $self->_set_own_id($json->{self}->{id}); - $self->_set_team_data($json->{team}); my $client = $self->client; From 36975d697e38851bc7096c40934d378b67785dd4 Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 3 Sep 2026 21:01:13 -0400 Subject: [PATCH 3/7] wip --- lib/Synergy/Channel/Slack.pm | 2 +- lib/Synergy/External/Slack.pm | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/Synergy/Channel/Slack.pm b/lib/Synergy/Channel/Slack.pm index 4fffc415..5d9c7138 100644 --- a/lib/Synergy/Channel/Slack.pm +++ b/lib/Synergy/Channel/Slack.pm @@ -144,7 +144,7 @@ sub _mk_frame_handler ($self) { } if ($slack_event->{type} eq 'hello') { - $Logger->log("Got 'hello' from Slack RTM!"); + $Logger->log("Got 'hello' from Slack Socket API!"); return; } diff --git a/lib/Synergy/External/Slack.pm b/lib/Synergy/External/Slack.pm index 172038fa..fc0ec98a 100644 --- a/lib/Synergy/External/Slack.pm +++ b/lib/Synergy/External/Slack.pm @@ -255,6 +255,9 @@ sub handle_frame ($self, $slack_event) { # These are the only way we'll ever hear about somebody who joined, or # changed their name, after we started up. Without them, we'd go on calling # them "" until the next restart. -- rjbs, 2026-08-19 + + $Logger->log(['handle_frame: %s', Dumper $slack_event ]); + my $type = $slack_event->{type} // ''; if ($type eq 'team_join' or $type eq 'user_change') { From 7b5dedcfa74e51d32a4ceb6305b534dc7bc30033 Mon Sep 17 00:00:00 2001 From: Ricardo Signes Date: Fri, 4 Sep 2026 11:34:36 +1000 Subject: [PATCH 4/7] wipwipwip --- lib/Synergy/External/Slack.pm | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/Synergy/External/Slack.pm b/lib/Synergy/External/Slack.pm index fc0ec98a..cd711a8f 100644 --- a/lib/Synergy/External/Slack.pm +++ b/lib/Synergy/External/Slack.pm @@ -204,7 +204,8 @@ async sub connect ($self) { notifier_name => 'slack-ping', interval => 10, on_tick => sub { - $self->send_frame({ type => 'ping' }); + $Logger->log("we will not ping"); + #$self->send_frame({ type => 'ping' }); } ); @@ -256,7 +257,7 @@ sub handle_frame ($self, $slack_event) { # changed their name, after we started up. Without them, we'd go on calling # them "" until the next restart. -- rjbs, 2026-08-19 - $Logger->log(['handle_frame: %s', Dumper $slack_event ]); + $Logger->log(['handle_frame: %s', $slack_event ]); my $type = $slack_event->{type} // ''; @@ -360,13 +361,15 @@ sub _send_plain_text ($self, $channel, $text) { $channel = $self->dm_channel_for_address($channel); } - my $f = $self->send_frame({ - type => 'message', + my %args = ( channel => $channel, + as_user => \1, text => $text, - }); + ); - return $f; + my $http_future = $self->api_call('chat.postMessage', \%args); + + return $http_future; } sub _send_rich_text ($self, $channel, $rich, $alts) { From bb707815ef55d870474400e044e861b9032b478c Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 3 Sep 2026 22:34:53 -0400 Subject: [PATCH 5/7] ignore this dir to make it harder to commit secrets --- eg/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 eg/.gitignore diff --git a/eg/.gitignore b/eg/.gitignore new file mode 100644 index 00000000..72e8ffc0 --- /dev/null +++ b/eg/.gitignore @@ -0,0 +1 @@ +* From 25270a467b3265b03b1dec3d512089500a67851a Mon Sep 17 00:00:00 2001 From: Luke Date: Thu, 3 Sep 2026 22:53:55 -0400 Subject: [PATCH 6/7] ack events, and do not expect acks to be acked again --- lib/Synergy/External/Slack.pm | 49 +++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 16 deletions(-) diff --git a/lib/Synergy/External/Slack.pm b/lib/Synergy/External/Slack.pm index cd711a8f..26eab96e 100644 --- a/lib/Synergy/External/Slack.pm +++ b/lib/Synergy/External/Slack.pm @@ -222,34 +222,42 @@ sub send_frame ($self, $frame) { my $frame_id = $i++; $frame->{id} = $frame_id; + $Logger->log(['send_frame: %s', Dumper $frame]); + if ($self->connected) { + $Logger->log('sent frame'); $self->client->send_frame(masked => 1, buffer => encode_json($frame)); } else { + $Logger->log('queued frame'); # Save it til after we've successfully reconnected $self->queue_frame($frame); } - my $f = $self->loop->new_future; - $self->pending_frames->{$frame_id} = $f; + unless ($frame->{envelope_id}) { - my $timeout = $self->loop->timeout_future(after => 3); - $timeout->on_fail(sub { - $Logger->log("failed to get response from slack; trying to reconnect"); + my $f = $self->loop->new_future; + $self->pending_frames->{$frame_id} = $f; - # XXX Blocking here is crappy. This is another place where we've pushed - # the "where is it async" around under the carpet, but haven't fully ironed - # out the lump yet. -- rjbs, 2023-10-10 - $self->client->close; - $self->connect->get; - # Also fail any pending futures for this frame. - my $f = delete $self->pending_frames->{$frame_id}; - $f->fail("timed out on connection to slack") if $f; - }); + my $timeout = $self->loop->timeout_future(after => 10); + $timeout->on_fail(sub { + $Logger->log("failed to get response from slack; trying to reconnect"); - $self->pending_timeouts->{$frame_id} = $timeout; + # XXX Blocking here is crappy. This is another place where we've pushed + # the "where is it async" around under the carpet, but haven't fully ironed + # out the lump yet. -- rjbs, 2023-10-10 + $self->client->close; + $self->connect->get; - return $f; + # Also fail any pending futures for this frame. + my $f = delete $self->pending_frames->{$frame_id}; + $f->fail("timed out on connection to slack") if $f; + }); + + $self->pending_timeouts->{$frame_id} = $timeout; + + return $f; + } } sub handle_frame ($self, $slack_event) { @@ -260,6 +268,15 @@ sub handle_frame ($self, $slack_event) { $Logger->log(['handle_frame: %s', $slack_event ]); my $type = $slack_event->{type} // ''; + my $envelope = $slack_event->{envelope_id}; + + # acknowledge frame + if ($envelope) { + $self->send_frame({ + type => $type, + envelope_id => $slack_event->{envelope_id}, + }); + } if ($type eq 'team_join' or $type eq 'user_change') { $self->_update_user($slack_event->{user}); From efdfa44ce435af889f121b83eccf84a001b07aa4 Mon Sep 17 00:00:00 2001 From: Luke Date: Fri, 4 Sep 2026 00:32:59 -0400 Subject: [PATCH 7/7] reply processing --- lib/Synergy/Channel/Slack.pm | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/Synergy/Channel/Slack.pm b/lib/Synergy/Channel/Slack.pm index 5d9c7138..86df2d76 100644 --- a/lib/Synergy/Channel/Slack.pm +++ b/lib/Synergy/Channel/Slack.pm @@ -6,6 +6,7 @@ use utf8; use Future::AsyncAwait; use JSON::MaybeXS; use IO::Async::Timer::Periodic; +use Data::Dumper::Concise; use Synergy::External::Slack; use Synergy::Event; @@ -125,15 +126,24 @@ sub _mk_frame_handler ($self) { return sub ($client, $frame) { return unless $frame; - my $slack_event; - unless (eval { $slack_event = $JSON->decode($frame) }) { + $Logger->log(['we got a frame: %s', $frame]); + + my $frame_data; + unless (eval { $frame_data = $JSON->decode($frame) }) { $Logger->log("error decoding frame content: <$frame> <$@>"); return; } # This is silly, but Websocket::Client's on_frame isn't a stack of # subs to call, it's only a single sub. -- michael, 2019-02-03 - $self->slack->handle_frame($slack_event); + $self->slack->handle_frame($frame_data); + + my $slack_event = $frame_data->{payload}->{event}; + + if (!$slack_event) { + $Logger->log('no event in:', $frame_data); + return; + } if (! $slack_event->{type} && $slack_event->{reply_to}) { unless ($slack_event->{ok}) { @@ -377,11 +387,24 @@ sub send_ephemeral_message ($self, $channel, $user, $text) { } sub note_reply ($self, $event, $future, $args = {}) { + + $Logger->log(['noting reply: %s', Dumper($event->transport_data)]); + my $ts = $event->transport_data->{ts}; return unless $ts; $future->on_done(sub ($data) { - unless ($data->{type} eq 'slack') { + $Logger->log(['reply data: %s', Dumper($data)]); + + my $decoded = $data->decoded_content({charset => 'none'}); + my $dejsond; + unless (eval { $dejsond = $JSON->decode($decoded) }) { + $Logger->log("error decoding response content: <$decoded> <$@>"); + return; + } + $Logger->log(['response: %s', $dejsond]); + + unless ($dejsond->{message}) { $Logger->log([ "got bizarre type back from slack future: %s", $data @@ -391,10 +414,10 @@ sub note_reply ($self, $event, $future, $args = {}) { # Slack reactions results just have { ok: true } # -- michael, 2019-02-05 - return unless $data->{transport_data}{ts}; + return unless $dejsond->{ts}; $self->add_reply($event, { - reply_ts => $data->{transport_data}{ts}, + reply_ts => $dejsond->{ts}, was_error => $args->{was_error} ? 1 : 0, }); });