Skip to content

Commit 9dd4f69

Browse files
authored
Merge pull request #10 from rohitcoder/bug-fix/slack-rate-limit
Fixed slack ratelimit issue
2 parents a6d2569 + 5b2df82 commit 9dd4f69

File tree

2 files changed

+32
-17
lines changed

2 files changed

+32
-17
lines changed

hawk_scanner/commands/slack.py

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ def connect_slack(args, token):
2222
system.print_error(args, f"Failed to connect to Slack with error: {e.response['error']}")
2323
return None
2424

25+
2526
def check_slack_messages(args, client, patterns, profile_name, channel_types, channel_ids=None, limit_mins=60, archived_channels=False):
2627
results = []
2728
try:
@@ -39,12 +40,26 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
3940
system.print_info(args, f"Current Time: {current_time_readable}")
4041
system.print_info(args, f"Fetching messages from the last {limit_mins} minutes (Oldest Time: {oldest_time_readable}, Unix: {int(oldest_time)})")
4142

43+
# Helper function to handle rate limits
44+
hawk_args = args
45+
def rate_limit_retry(func, *args, **kwargs):
46+
while True:
47+
try:
48+
return func(*args, **kwargs)
49+
except SlackApiError as e:
50+
if e.response["error"] == "ratelimited":
51+
retry_after = int(e.response.headers.get("Retry-After", 1))
52+
system.print_info(hawk_args, f"Rate limited. Retrying after {retry_after} seconds...")
53+
time.sleep(retry_after)
54+
else:
55+
raise
56+
4257
# Get all channels of specified types
4358
channels = []
4459

4560
if not channel_ids:
4661
system.print_info(args, "Getting all channels because no channel_ids provided")
47-
62+
4863
# Pagination logic to fetch all non-archived channels
4964
cursor = None
5065
while True:
@@ -53,17 +68,19 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
5368
system.print_debug(args, f"Considering archived channels, you may want to set archived_channels to False")
5469
else:
5570
system.print_debug(args, f"Skipping archived channels, you may want to set archived_channels to True")
56-
response = client.conversations_list(
57-
types=channel_types,
58-
limit=1000,
59-
cursor=cursor,
71+
72+
response = rate_limit_retry(
73+
client.conversations_list,
74+
types=channel_types,
75+
limit=1000,
76+
cursor=cursor,
6077
exclude_archived=not archived_channels
6178
)
6279
channels.extend(response.get("channels", []))
63-
80+
6481
# Update the cursor for the next batch
6582
cursor = response.get("response_metadata", {}).get("next_cursor")
66-
83+
6784
if not cursor: # Break the loop if there are no more channels to fetch
6885
break
6986
except SlackApiError as e:
@@ -73,14 +90,11 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
7390
system.print_info(args, "Getting channels by channel_ids")
7491
for channel_id in channel_ids:
7592
try:
76-
channel = client.conversations_info(channel=channel_id)["channel"]
77-
## if archived_channels is set to True, include archived channels
93+
channel = rate_limit_retry(client.conversations_info, channel=channel_id)["channel"]
7894
if archived_channels or not channel.get("is_archived"):
79-
system.print_debug(args, f"Considering archived channels, you may want to set archived_channels to False")
8095
channels.append(channel)
8196
else:
8297
system.print_debug(args, f"Skipping archived channel: {channel_id}")
83-
8498
except SlackApiError as e:
8599
system.print_error(args, f"Failed to fetch channel with id {channel_id} with error: {e.response['error']}")
86100

@@ -95,7 +109,7 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
95109

96110
# Get messages from the channel within the time range
97111
system.print_info(args, f"Checking messages in channel {channel_name} ({channel_id})")
98-
messages = client.conversations_history(channel=channel_id, oldest=oldest_time)["messages"]
112+
messages = rate_limit_retry(client.conversations_history, channel=channel_id, oldest=oldest_time)["messages"]
99113
for message in messages:
100114
user = message.get("user", "")
101115
text = message.get("text")
@@ -106,7 +120,7 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
106120
file_addr = download_file(args, client, file, folder_path)
107121
if file_addr:
108122
system.print_debug(args, f"Checking file: {file_addr}")
109-
matches = system.read_match_strings(args, file_addr, 'slack')
123+
matches = system.read_match_strings(args, file_addr, 'slack')
110124
if matches:
111125
for match in matches:
112126
results.append({
@@ -120,7 +134,7 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
120134
'message_link': workspace_url + f"/archives/{channel_id}/p{message_ts.replace('.', '')}",
121135
'data_source': 'slack'
122136
})
123-
137+
124138
# Check main message for matches
125139
if text:
126140
matches = system.match_strings(args, text)
@@ -140,7 +154,7 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
140154

141155
if "thread_ts" in message:
142156
thread_ts = message["thread_ts"]
143-
replies = client.conversations_replies(channel=channel_id, ts=thread_ts, oldest=oldest_time)["messages"]
157+
replies = rate_limit_retry(client.conversations_replies, channel=channel_id, ts=thread_ts, oldest=oldest_time)["messages"]
144158
for reply in replies:
145159
if reply["ts"] != thread_ts: # Skip the parent message
146160
reply_user = reply.get("user", "")
@@ -153,7 +167,7 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
153167
file_addr = download_file(args, client, file, folder_path)
154168
if file_addr:
155169
system.print_debug(args, f"Checking file: {file_addr}")
156-
matches = system.read_match_strings(args, file_addr, 'slack')
170+
matches = system.read_match_strings(args, file_addr, 'slack')
157171
if matches:
158172
for match in matches:
159173
results.append({
@@ -192,6 +206,7 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
192206

193207

194208

209+
195210
def download_file(args, client, file_info, folder_path) -> str:
196211
try:
197212
# Ensure the folder exists

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
VERSION = "0.3.26"
1+
VERSION = "0.3.26-ratelimit-fix"
22

33
from setuptools import setup, find_packages
44

0 commit comments

Comments
 (0)