@@ -22,6 +22,7 @@ def connect_slack(args, token):
22
22
system .print_error (args , f"Failed to connect to Slack with error: { e .response ['error' ]} " )
23
23
return None
24
24
25
+
25
26
def check_slack_messages (args , client , patterns , profile_name , channel_types , channel_ids = None , limit_mins = 60 , archived_channels = False ):
26
27
results = []
27
28
try :
@@ -39,12 +40,26 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
39
40
system .print_info (args , f"Current Time: { current_time_readable } " )
40
41
system .print_info (args , f"Fetching messages from the last { limit_mins } minutes (Oldest Time: { oldest_time_readable } , Unix: { int (oldest_time )} )" )
41
42
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
+
42
57
# Get all channels of specified types
43
58
channels = []
44
59
45
60
if not channel_ids :
46
61
system .print_info (args , "Getting all channels because no channel_ids provided" )
47
-
62
+
48
63
# Pagination logic to fetch all non-archived channels
49
64
cursor = None
50
65
while True :
@@ -53,17 +68,19 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
53
68
system .print_debug (args , f"Considering archived channels, you may want to set archived_channels to False" )
54
69
else :
55
70
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 ,
60
77
exclude_archived = not archived_channels
61
78
)
62
79
channels .extend (response .get ("channels" , []))
63
-
80
+
64
81
# Update the cursor for the next batch
65
82
cursor = response .get ("response_metadata" , {}).get ("next_cursor" )
66
-
83
+
67
84
if not cursor : # Break the loop if there are no more channels to fetch
68
85
break
69
86
except SlackApiError as e :
@@ -73,14 +90,11 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
73
90
system .print_info (args , "Getting channels by channel_ids" )
74
91
for channel_id in channel_ids :
75
92
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" ]
78
94
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" )
80
95
channels .append (channel )
81
96
else :
82
97
system .print_debug (args , f"Skipping archived channel: { channel_id } " )
83
-
84
98
except SlackApiError as e :
85
99
system .print_error (args , f"Failed to fetch channel with id { channel_id } with error: { e .response ['error' ]} " )
86
100
@@ -95,7 +109,7 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
95
109
96
110
# Get messages from the channel within the time range
97
111
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" ]
99
113
for message in messages :
100
114
user = message .get ("user" , "" )
101
115
text = message .get ("text" )
@@ -106,7 +120,7 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
106
120
file_addr = download_file (args , client , file , folder_path )
107
121
if file_addr :
108
122
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' )
110
124
if matches :
111
125
for match in matches :
112
126
results .append ({
@@ -120,7 +134,7 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
120
134
'message_link' : workspace_url + f"/archives/{ channel_id } /p{ message_ts .replace ('.' , '' )} " ,
121
135
'data_source' : 'slack'
122
136
})
123
-
137
+
124
138
# Check main message for matches
125
139
if text :
126
140
matches = system .match_strings (args , text )
@@ -140,7 +154,7 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
140
154
141
155
if "thread_ts" in message :
142
156
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" ]
144
158
for reply in replies :
145
159
if reply ["ts" ] != thread_ts : # Skip the parent message
146
160
reply_user = reply .get ("user" , "" )
@@ -153,7 +167,7 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
153
167
file_addr = download_file (args , client , file , folder_path )
154
168
if file_addr :
155
169
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' )
157
171
if matches :
158
172
for match in matches :
159
173
results .append ({
@@ -192,6 +206,7 @@ def check_slack_messages(args, client, patterns, profile_name, channel_types, ch
192
206
193
207
194
208
209
+
195
210
def download_file (args , client , file_info , folder_path ) -> str :
196
211
try :
197
212
# Ensure the folder exists
0 commit comments