ezii-discord 0.test
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +56 -0
- data/TUTORIAL.md +2 -0
- data/chat-bot-1.rb +701 -0
- data/ezii-discord-integration.gemspec +14 -0
- data/lib/ezii_curl_manager.rb +58 -0
- data/lib/test/test_ezii_curl_manager.rb +7 -0
- data/test/test-chat-bot-1.rb +10 -0
- metadata +50 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 16eff586b4ef4f772d1c6626b7fdd51a70fb4582922b0b87c1289819a2ea99d1
|
4
|
+
data.tar.gz: eed8da7949bedf39add6d15153a7e4c7dd3184807cfaae84248f3a8cae6ae420
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: dd2b89bd23c6d60e77efce60c9c14d8eff7ca58b5e7fd54a2d83cb22be7cc5096bc4eb62ce8343e917d34598c16abbab0f971353631c29b9b71f27f36f9d95d6
|
7
|
+
data.tar.gz: 9659f623af82656d3efd416a1acf2ea541892022783f30a158543832a93aac2bcdf1f27839af5c22eebc6f726d7bd074cf1be6bc71027e9f4e60bb8e49040dad
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/eZii-jester-data/ladder-gem.git
|
3
|
+
revision: f387e0fd49f1a0dffea5488afc0366bba1c8b713
|
4
|
+
specs:
|
5
|
+
ladder (11.test)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
specs:
|
9
|
+
byebug (11.0.1)
|
10
|
+
discordrb (3.3.0)
|
11
|
+
discordrb-webhooks (~> 3.3.0)
|
12
|
+
ffi (>= 1.9.24)
|
13
|
+
opus-ruby
|
14
|
+
rbnacl (~> 3.4.0)
|
15
|
+
rest-client (>= 2.1.0.rc1)
|
16
|
+
websocket-client-simple (>= 0.3.0)
|
17
|
+
discordrb-webhooks (3.3.0)
|
18
|
+
rest-client (>= 2.1.0.rc1)
|
19
|
+
domain_name (0.5.20190701)
|
20
|
+
unf (>= 0.0.5, < 1.0.0)
|
21
|
+
event_emitter (0.2.6)
|
22
|
+
ffi (1.11.1)
|
23
|
+
http-accept (1.7.0)
|
24
|
+
http-cookie (1.0.3)
|
25
|
+
domain_name (~> 0.5)
|
26
|
+
mime-types (3.3)
|
27
|
+
mime-types-data (~> 3.2015)
|
28
|
+
mime-types-data (3.2019.0904)
|
29
|
+
netrc (0.11.0)
|
30
|
+
opus-ruby (1.0.1)
|
31
|
+
ffi
|
32
|
+
rbnacl (3.4.0)
|
33
|
+
ffi
|
34
|
+
rest-client (2.1.0.rc1)
|
35
|
+
http-accept (>= 1.7.0, < 2.0)
|
36
|
+
http-cookie (>= 1.0.2, < 2.0)
|
37
|
+
mime-types (>= 1.16, < 4.0)
|
38
|
+
netrc (~> 0.8)
|
39
|
+
unf (0.1.4)
|
40
|
+
unf_ext
|
41
|
+
unf_ext (0.0.7.6)
|
42
|
+
websocket (1.2.8)
|
43
|
+
websocket-client-simple (0.3.0)
|
44
|
+
event_emitter
|
45
|
+
websocket
|
46
|
+
|
47
|
+
PLATFORMS
|
48
|
+
ruby
|
49
|
+
|
50
|
+
DEPENDENCIES
|
51
|
+
byebug
|
52
|
+
discordrb
|
53
|
+
ladder (= 11.test)!
|
54
|
+
|
55
|
+
BUNDLED WITH
|
56
|
+
1.17.2
|
data/TUTORIAL.md
ADDED
data/chat-bot-1.rb
ADDED
@@ -0,0 +1,701 @@
|
|
1
|
+
require 'ladder'
|
2
|
+
require 'discordrb'
|
3
|
+
|
4
|
+
class FalseClass
|
5
|
+
def false?
|
6
|
+
self == false
|
7
|
+
end
|
8
|
+
end
|
9
|
+
class TrueClass
|
10
|
+
def false?
|
11
|
+
self == false
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
class GBotResponseNotCapture < Exception
|
17
|
+
end
|
18
|
+
|
19
|
+
module EZIIDiscordIntegration
|
20
|
+
|
21
|
+
TEST_COMMAND_STRING = "5 results for te123§§st"
|
22
|
+
MESSAGE = "gbot: #{TEST_COMMAND_STRING} | filter by curl response time | top 1"
|
23
|
+
|
24
|
+
|
25
|
+
VIRTUAL_EXCEPTION = {}
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
USER_ID_HOLDER = {gbot_id: nil}
|
30
|
+
FIRST_GBOT_MESSAGE_HOLDER = {first_gbot_message_id: nil}
|
31
|
+
|
32
|
+
|
33
|
+
ERR_ID_0 = "search string for gbot is not a string"# ,
|
34
|
+
ERR_ID_1 = "respoonse not delivered within 1 second"# ,
|
35
|
+
ERR_ID_2 = "Gbot discord user id was not configured, start the assignment after bot restart by '!pipeline gbot-id-capture"# ,
|
36
|
+
ERR_ID_3 = "Gbot didn't respond within timeframe"# ,
|
37
|
+
ERR_ID_4 = "Gbot answered more than once within timeframe (this bot must run in a channel where only this bot is allowed to write messages to gbot)"# ,
|
38
|
+
ERR_ID_5 = "ID of all following gbot messages must not equal the id of the first gbot message"
|
39
|
+
ERR_ID_6 = "ID of first gbot message received by this program must not be nil"
|
40
|
+
ERR_ID_7 = "DISCORD_MESSAGES must be synced globally"
|
41
|
+
ERR_ID_8 = "Curl not working dum dum"
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
def self.monkeypatching
|
46
|
+
yield
|
47
|
+
end
|
48
|
+
|
49
|
+
monkeypatching do
|
50
|
+
module Discordrb
|
51
|
+
# Represents a Discord bot, including servers, users, etc.
|
52
|
+
class Bot
|
53
|
+
|
54
|
+
def handle_dispatch(type, data)
|
55
|
+
# Check whether there are still unavailable servers and there have been more than 10 seconds since READY
|
56
|
+
if @unavailable_servers && @unavailable_servers > 0 && (Time.now - @unavailable_timeout_time) > 10
|
57
|
+
# The server streaming timed out!
|
58
|
+
LOGGER.debug("Server streaming timed out with #{@unavailable_servers} servers remaining")
|
59
|
+
LOGGER.debug('Calling ready now because server loading is taking a long time. Servers may be unavailable due to an outage, or your bot is on very large servers.')
|
60
|
+
|
61
|
+
# Unset the unavailable server count so this doesn't get triggered again
|
62
|
+
@unavailable_servers = 0
|
63
|
+
|
64
|
+
notify_ready
|
65
|
+
end
|
66
|
+
|
67
|
+
case type
|
68
|
+
when :READY
|
69
|
+
# As READY may be called multiple times over a single process lifetime, we here need to reset the cache entirely
|
70
|
+
# to prevent possible inconsistencies, like objects referencing old versions of other objects which have been
|
71
|
+
# replaced.
|
72
|
+
init_cache
|
73
|
+
|
74
|
+
@profile = Profile.new(data['user'], self)
|
75
|
+
|
76
|
+
# Initialize servers
|
77
|
+
@servers = {}
|
78
|
+
|
79
|
+
# Count unavailable servers
|
80
|
+
@unavailable_servers = 0
|
81
|
+
|
82
|
+
data['guilds'].each do |element|
|
83
|
+
# Check for true specifically because unavailable=false indicates that a previously unavailable server has
|
84
|
+
# come online
|
85
|
+
if element['unavailable'].is_a? TrueClass
|
86
|
+
@unavailable_servers += 1
|
87
|
+
|
88
|
+
# Ignore any unavailable servers
|
89
|
+
next
|
90
|
+
end
|
91
|
+
|
92
|
+
ensure_server(element)
|
93
|
+
end
|
94
|
+
|
95
|
+
# Add PM and group channels
|
96
|
+
data['private_channels'].each do |element|
|
97
|
+
channel = ensure_channel(element)
|
98
|
+
if channel.pm?
|
99
|
+
@pm_channels[channel.recipient.id] = channel
|
100
|
+
else
|
101
|
+
@channels[channel.id] = channel
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Don't notify yet if there are unavailable servers because they need to get available before the bot truly has
|
106
|
+
# all the data
|
107
|
+
if @unavailable_servers.zero?
|
108
|
+
# No unavailable servers - we're ready!
|
109
|
+
notify_ready
|
110
|
+
end
|
111
|
+
|
112
|
+
@ready_time = Time.now
|
113
|
+
@unavailable_timeout_time = Time.now
|
114
|
+
when :GUILD_MEMBERS_CHUNK
|
115
|
+
id = data['guild_id'].to_i
|
116
|
+
server = server(id)
|
117
|
+
server.process_chunk(data['members'])
|
118
|
+
when :MESSAGE_CREATE
|
119
|
+
|
120
|
+
ladder(data)
|
121
|
+
|
122
|
+
|
123
|
+
if ignored?(data['author']['id'].to_i)
|
124
|
+
debug("Ignored author with ID #{data['author']['id']}")
|
125
|
+
return
|
126
|
+
end
|
127
|
+
|
128
|
+
if @ignore_bots && data['author']['bot']
|
129
|
+
debug("Ignored Bot account with ID #{data['author']['id']}")
|
130
|
+
return
|
131
|
+
end
|
132
|
+
|
133
|
+
# If create_message is overwritten with a method that returns the parsed message, use that instead, so we don't
|
134
|
+
# parse the message twice (which is just thrown away performance)
|
135
|
+
message = create_message(data)
|
136
|
+
message = Message.new(data, self) unless message.is_a? Message
|
137
|
+
|
138
|
+
return if message.from_bot? && !should_parse_self
|
139
|
+
|
140
|
+
event = MessageEvent.new(message, self)
|
141
|
+
raise_event(event)
|
142
|
+
|
143
|
+
if message.mentions.any? { |user| user.id == @profile.id }
|
144
|
+
event = MentionEvent.new(message, self)
|
145
|
+
raise_event(event)
|
146
|
+
end
|
147
|
+
|
148
|
+
if message.channel.private?
|
149
|
+
event = PrivateMessageEvent.new(message, self)
|
150
|
+
raise_event(event)
|
151
|
+
end
|
152
|
+
when :MESSAGE_UPDATE
|
153
|
+
update_message(data)
|
154
|
+
|
155
|
+
message = Message.new(data, self)
|
156
|
+
return if message.from_bot? && !should_parse_self
|
157
|
+
|
158
|
+
unless message.author
|
159
|
+
LOGGER.debug("Edited a message with nil author! Content: #{message.content.inspect}, channel: #{message.channel.inspect}")
|
160
|
+
return
|
161
|
+
end
|
162
|
+
|
163
|
+
event = MessageEditEvent.new(message, self)
|
164
|
+
raise_event(event)
|
165
|
+
when :MESSAGE_DELETE
|
166
|
+
delete_message(data)
|
167
|
+
|
168
|
+
event = MessageDeleteEvent.new(data, self)
|
169
|
+
raise_event(event)
|
170
|
+
when :MESSAGE_DELETE_BULK
|
171
|
+
debug("MESSAGE_DELETE_BULK will raise #{data['ids'].length} events")
|
172
|
+
|
173
|
+
data['ids'].each do |single_id|
|
174
|
+
# Form a data hash for a single ID so the methods get what they want
|
175
|
+
single_data = {
|
176
|
+
'id' => single_id,
|
177
|
+
'channel_id' => data['channel_id']
|
178
|
+
}
|
179
|
+
|
180
|
+
# Raise as normal
|
181
|
+
delete_message(single_data)
|
182
|
+
|
183
|
+
event = MessageDeleteEvent.new(single_data, self)
|
184
|
+
raise_event(event)
|
185
|
+
end
|
186
|
+
when :TYPING_START
|
187
|
+
start_typing(data)
|
188
|
+
|
189
|
+
begin
|
190
|
+
event = TypingEvent.new(data, self)
|
191
|
+
raise_event(event)
|
192
|
+
rescue Discordrb::Errors::NoPermission
|
193
|
+
debug 'Typing started in channel the bot has no access to, ignoring'
|
194
|
+
end
|
195
|
+
when :MESSAGE_REACTION_ADD
|
196
|
+
add_message_reaction(data)
|
197
|
+
|
198
|
+
return if profile.id == data['user_id'].to_i && !should_parse_self
|
199
|
+
|
200
|
+
event = ReactionAddEvent.new(data, self)
|
201
|
+
raise_event(event)
|
202
|
+
when :MESSAGE_REACTION_REMOVE
|
203
|
+
remove_message_reaction(data)
|
204
|
+
|
205
|
+
return if profile.id == data['user_id'].to_i && !should_parse_self
|
206
|
+
|
207
|
+
event = ReactionRemoveEvent.new(data, self)
|
208
|
+
raise_event(event)
|
209
|
+
when :MESSAGE_REACTION_REMOVE_ALL
|
210
|
+
remove_all_message_reactions(data)
|
211
|
+
|
212
|
+
event = ReactionRemoveAllEvent.new(data, self)
|
213
|
+
raise_event(event)
|
214
|
+
when :PRESENCE_UPDATE
|
215
|
+
# Ignore friends list presences
|
216
|
+
return unless data['guild_id']
|
217
|
+
|
218
|
+
now_playing = data['game'].nil? ? nil : data['game']['name']
|
219
|
+
presence_user = @users[data['user']['id'].to_i]
|
220
|
+
played_before = presence_user.nil? ? nil : presence_user.game
|
221
|
+
update_presence(data)
|
222
|
+
|
223
|
+
event = if now_playing != played_before
|
224
|
+
PlayingEvent.new(data, self)
|
225
|
+
else
|
226
|
+
PresenceEvent.new(data, self)
|
227
|
+
end
|
228
|
+
|
229
|
+
raise_event(event)
|
230
|
+
when :VOICE_STATE_UPDATE
|
231
|
+
old_channel_id = update_voice_state(data)
|
232
|
+
|
233
|
+
event = VoiceStateUpdateEvent.new(data, old_channel_id, self)
|
234
|
+
raise_event(event)
|
235
|
+
when :VOICE_SERVER_UPDATE
|
236
|
+
update_voice_server(data)
|
237
|
+
|
238
|
+
# no event as this is irrelevant to users
|
239
|
+
when :CHANNEL_CREATE
|
240
|
+
create_channel(data)
|
241
|
+
|
242
|
+
event = ChannelCreateEvent.new(data, self)
|
243
|
+
raise_event(event)
|
244
|
+
when :CHANNEL_UPDATE
|
245
|
+
update_channel(data)
|
246
|
+
|
247
|
+
event = ChannelUpdateEvent.new(data, self)
|
248
|
+
raise_event(event)
|
249
|
+
when :CHANNEL_DELETE
|
250
|
+
delete_channel(data)
|
251
|
+
|
252
|
+
event = ChannelDeleteEvent.new(data, self)
|
253
|
+
raise_event(event)
|
254
|
+
when :CHANNEL_RECIPIENT_ADD
|
255
|
+
add_recipient(data)
|
256
|
+
|
257
|
+
event = ChannelRecipientAddEvent.new(data, self)
|
258
|
+
raise_event(event)
|
259
|
+
when :CHANNEL_RECIPIENT_REMOVE
|
260
|
+
remove_recipient(data)
|
261
|
+
|
262
|
+
event = ChannelRecipientRemoveEvent.new(data, self)
|
263
|
+
raise_event(event)
|
264
|
+
when :GUILD_MEMBER_ADD
|
265
|
+
add_guild_member(data)
|
266
|
+
|
267
|
+
event = ServerMemberAddEvent.new(data, self)
|
268
|
+
raise_event(event)
|
269
|
+
when :GUILD_MEMBER_UPDATE
|
270
|
+
update_guild_member(data)
|
271
|
+
|
272
|
+
event = ServerMemberUpdateEvent.new(data, self)
|
273
|
+
raise_event(event)
|
274
|
+
when :GUILD_MEMBER_REMOVE
|
275
|
+
delete_guild_member(data)
|
276
|
+
|
277
|
+
event = ServerMemberDeleteEvent.new(data, self)
|
278
|
+
raise_event(event)
|
279
|
+
when :GUILD_BAN_ADD
|
280
|
+
add_user_ban(data)
|
281
|
+
|
282
|
+
event = UserBanEvent.new(data, self)
|
283
|
+
raise_event(event)
|
284
|
+
when :GUILD_BAN_REMOVE
|
285
|
+
remove_user_ban(data)
|
286
|
+
|
287
|
+
event = UserUnbanEvent.new(data, self)
|
288
|
+
raise_event(event)
|
289
|
+
when :GUILD_ROLE_UPDATE
|
290
|
+
update_guild_role(data)
|
291
|
+
|
292
|
+
event = ServerRoleUpdateEvent.new(data, self)
|
293
|
+
raise_event(event)
|
294
|
+
when :GUILD_ROLE_CREATE
|
295
|
+
create_guild_role(data)
|
296
|
+
|
297
|
+
event = ServerRoleCreateEvent.new(data, self)
|
298
|
+
raise_event(event)
|
299
|
+
when :GUILD_ROLE_DELETE
|
300
|
+
delete_guild_role(data)
|
301
|
+
|
302
|
+
event = ServerRoleDeleteEvent.new(data, self)
|
303
|
+
raise_event(event)
|
304
|
+
when :GUILD_CREATE
|
305
|
+
create_guild(data)
|
306
|
+
|
307
|
+
# Check for false specifically (no data means the server has never been unavailable)
|
308
|
+
if data['unavailable'].is_a? FalseClass
|
309
|
+
@unavailable_servers -= 1 if @unavailable_servers
|
310
|
+
@unavailable_timeout_time = Time.now
|
311
|
+
|
312
|
+
notify_ready if @unavailable_servers.zero?
|
313
|
+
|
314
|
+
# Return here so the event doesn't get triggered
|
315
|
+
return
|
316
|
+
end
|
317
|
+
|
318
|
+
event = ServerCreateEvent.new(data, self)
|
319
|
+
raise_event(event)
|
320
|
+
when :GUILD_UPDATE
|
321
|
+
update_guild(data)
|
322
|
+
|
323
|
+
event = ServerUpdateEvent.new(data, self)
|
324
|
+
raise_event(event)
|
325
|
+
when :GUILD_DELETE
|
326
|
+
delete_guild(data)
|
327
|
+
|
328
|
+
if data['unavailable'].is_a? TrueClass
|
329
|
+
LOGGER.warn("Server #{data['id']} is unavailable due to an outage!")
|
330
|
+
return # Don't raise an event
|
331
|
+
end
|
332
|
+
|
333
|
+
event = ServerDeleteEvent.new(data, self)
|
334
|
+
raise_event(event)
|
335
|
+
when :GUILD_EMOJIS_UPDATE
|
336
|
+
server_id = data['guild_id'].to_i
|
337
|
+
server = @servers[server_id]
|
338
|
+
old_emoji_data = server.emoji.clone
|
339
|
+
update_guild_emoji(data)
|
340
|
+
new_emoji_data = server.emoji
|
341
|
+
|
342
|
+
created_ids = new_emoji_data.keys - old_emoji_data.keys
|
343
|
+
deleted_ids = old_emoji_data.keys - new_emoji_data.keys
|
344
|
+
updated_ids = old_emoji_data.select do |k, v|
|
345
|
+
new_emoji_data[k] && (v.name != new_emoji_data[k].name || v.roles != new_emoji_data[k].roles)
|
346
|
+
end.keys
|
347
|
+
|
348
|
+
event = ServerEmojiChangeEvent.new(server, data, self)
|
349
|
+
raise_event(event)
|
350
|
+
|
351
|
+
created_ids.each do |e|
|
352
|
+
event = ServerEmojiCreateEvent.new(server, new_emoji_data[e], self)
|
353
|
+
raise_event(event)
|
354
|
+
end
|
355
|
+
|
356
|
+
deleted_ids.each do |e|
|
357
|
+
event = ServerEmojiDeleteEvent.new(server, old_emoji_data[e], self)
|
358
|
+
raise_event(event)
|
359
|
+
end
|
360
|
+
|
361
|
+
updated_ids.each do |e|
|
362
|
+
event = ServerEmojiUpdateEvent.new(server, old_emoji_data[e], new_emoji_data[e], self)
|
363
|
+
raise_event(event)
|
364
|
+
end
|
365
|
+
when :WEBHOOKS_UPDATE
|
366
|
+
event = WebhookUpdateEvent.new(data, self)
|
367
|
+
raise_event(event)
|
368
|
+
else
|
369
|
+
# another event that we don't support yet
|
370
|
+
debug "Event #{type} has been received but is unsupported. Raising UnknownEvent"
|
371
|
+
|
372
|
+
event = UnknownEvent.new(type, data, self)
|
373
|
+
raise_event(event)
|
374
|
+
end
|
375
|
+
|
376
|
+
# The existence of this array is checked before for performance reasons, since this has to be done for *every*
|
377
|
+
# dispatch.
|
378
|
+
if @event_handlers && @event_handlers[RawEvent]
|
379
|
+
event = RawEvent.new(type, data, self)
|
380
|
+
raise_event(event)
|
381
|
+
end
|
382
|
+
rescue Exception => e
|
383
|
+
LOGGER.error('Gateway message error!')
|
384
|
+
log_exception(e)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
|
390
|
+
|
391
|
+
def self.split_into_pipe_parts(message: '', pipe_unicode_symbol: '|')
|
392
|
+
message.split('|')
|
393
|
+
end
|
394
|
+
|
395
|
+
|
396
|
+
|
397
|
+
class PipelineDiscordBot
|
398
|
+
CURL_RESPONSES_HOLDER = {}
|
399
|
+
|
400
|
+
attr_reader :bot
|
401
|
+
|
402
|
+
|
403
|
+
def initialize
|
404
|
+
@bot = ::Discordrb::Bot.new token: ENV['BOT_TOKEN']
|
405
|
+
|
406
|
+
self.add_pipeline_command
|
407
|
+
self.add_gbot_id_fetch_command
|
408
|
+
end
|
409
|
+
|
410
|
+
def get_gbot_message(query, event, callback)
|
411
|
+
command = GbotCommandForBot2Bot.new(query, event)
|
412
|
+
capture = GbotCommandResponseCapture.new(command)
|
413
|
+
|
414
|
+
capture.command.send do
|
415
|
+
capture.pump_once do
|
416
|
+
if !capture.response.nil? && extract_urls_from_gbot_response(capture.response).any?
|
417
|
+
callback.call(capture.response)
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
422
|
+
|
423
|
+
def use(*args)
|
424
|
+
yield
|
425
|
+
end
|
426
|
+
|
427
|
+
def where_the_use_would_fail(*args)
|
428
|
+
yield
|
429
|
+
end
|
430
|
+
|
431
|
+
def §(*args)
|
432
|
+
yield if block_given?
|
433
|
+
end
|
434
|
+
|
435
|
+
ESSENTIAL_DECLARATINO_OF_LOCAL_VARIABLE = [self, 0]
|
436
|
+
|
437
|
+
def add_pipeline_command
|
438
|
+
bot.message(with_text: 'pipeline:') do |event|
|
439
|
+
|
440
|
+
if USER_ID_HOLDER[:gbot_id].nil?
|
441
|
+
event.respond("Please first initialize via !pipeline gbot-id-capture")
|
442
|
+
|
443
|
+
else
|
444
|
+
|
445
|
+
event.user.await(:pipeline_definition) do |pipeline_definition_message_event|
|
446
|
+
|
447
|
+
|
448
|
+
user_message = pipeline_definition_message_event.message.content
|
449
|
+
|
450
|
+
pipe_parts = EZIIDiscordIntegration.split_into_pipe_parts(message: MESSAGE.gsub('te123§§st', user_message), pipe_unicode_symbol: '|')
|
451
|
+
|
452
|
+
event.respond pipe_parts.inspect
|
453
|
+
|
454
|
+
pipeline = Pipeline.new
|
455
|
+
pipe_parts.each do |pipe_part| pipeline.add(pipe_part) end
|
456
|
+
|
457
|
+
|
458
|
+
|
459
|
+
pipeline.run { |message, left_commands_count, new_output_value_callback, last_output_value_callback|
|
460
|
+
|
461
|
+
|
462
|
+
|
463
|
+
event.respond("Commands to be run after this one: #{left_commands_count}, now running:")
|
464
|
+
|
465
|
+
thread = lambda { |est| est.call }
|
466
|
+
if message =~ /gbot/
|
467
|
+
get_gbot_message(
|
468
|
+
message.gsub('gbot:', ''),
|
469
|
+
event,
|
470
|
+
->(response_message) do
|
471
|
+
new_output_value_callback.call(response_message)
|
472
|
+
end)
|
473
|
+
|
474
|
+
|
475
|
+
end
|
476
|
+
|
477
|
+
|
478
|
+
if message =~ /curl/
|
479
|
+
CURL_RESPONSES_HOLDER[0] = lambda do |&block|
|
480
|
+
last_output_value_callback.call do |value|
|
481
|
+
block.call(prepare_curl_responses(value))
|
482
|
+
end
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
|
487
|
+
if message =~ /top/
|
488
|
+
CURL_RESPONSES_HOLDER[0].call do |value|
|
489
|
+
event.respond(value.wait_for_finish.winner)
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
}
|
494
|
+
end
|
495
|
+
|
496
|
+
end
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
require_relative './lib/ezii_curl_manager.rb'
|
501
|
+
def prepare_curl_responses(gbot_message)
|
502
|
+
cm = CurlManager.new( extract_urls_from_gbot_response( gbot_message ) )
|
503
|
+
|
504
|
+
cm.start_calls_in_background
|
505
|
+
|
506
|
+
|
507
|
+
return cm
|
508
|
+
end
|
509
|
+
|
510
|
+
|
511
|
+
def extract_urls_from_gbot_response(gbot_message)
|
512
|
+
return gbot_message.scan(/<([^>]*)>/)
|
513
|
+
end
|
514
|
+
|
515
|
+
|
516
|
+
def add_gbot_id_fetch_command
|
517
|
+
bot.message(content: '!pipeline gbot-id-capture') do |event|
|
518
|
+
event.respond("Type start to begin")
|
519
|
+
event.user.await(:start) do |start_event|
|
520
|
+
event.respond('gbot: get-id')
|
521
|
+
|
522
|
+
ladder { |data|
|
523
|
+
if(data['author']['username'] == 'GBot')
|
524
|
+
USER_ID_HOLDER[:gbot_id] ||= data['author']['id']
|
525
|
+
FIRST_GBOT_MESSAGE_HOLDER[:first_gbot_message_id] ||= data['id']
|
526
|
+
|
527
|
+
event.respond('Google Bot Discord ID is ' + USER_ID_HOLDER[:gbot_id].inspect)
|
528
|
+
end
|
529
|
+
}
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
end
|
534
|
+
|
535
|
+
|
536
|
+
class Pipeline
|
537
|
+
attr_accessor :block
|
538
|
+
def initialize
|
539
|
+
@queue = []
|
540
|
+
end
|
541
|
+
|
542
|
+
def add(execute)
|
543
|
+
# §(USE_PUSH_OVER_UNSHIFT_FOR: QUEUE_IMPLEEMENTATION)
|
544
|
+
@queue.push(execute)
|
545
|
+
# end
|
546
|
+
end
|
547
|
+
|
548
|
+
def run
|
549
|
+
last_item = nil
|
550
|
+
while @queue.any?
|
551
|
+
last_item = yield(@queue.shift, @queue.size, new_output_value_callback, last_output_value_callback)
|
552
|
+
end
|
553
|
+
end
|
554
|
+
|
555
|
+
|
556
|
+
def new_output_value_callback
|
557
|
+
return Proc.new do |new_value|
|
558
|
+
self.block.call(new_value)
|
559
|
+
end
|
560
|
+
end
|
561
|
+
|
562
|
+
def last_output_value_callback
|
563
|
+
return Proc.new do |&block|
|
564
|
+
self.block = block
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
def inspect
|
569
|
+
"""
|
570
|
+
First run command #{@queue[0]}
|
571
|
+
Second run command #{@queue[1]}
|
572
|
+
Third run command #{@queue[2]}
|
573
|
+
"""
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
module Pipeline::ExpectResponseWithin
|
578
|
+
module ClassMethods
|
579
|
+
def timeframe_for_response=(timeframe_in_seconds)
|
580
|
+
@timeframe_in_seconds = timeframe_in_seconds
|
581
|
+
end
|
582
|
+
|
583
|
+
def timeframe_for_response
|
584
|
+
@timeframe_in_seconds
|
585
|
+
end
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
|
590
|
+
|
591
|
+
class GbotCommandResponseCapture
|
592
|
+
attr_accessor :command
|
593
|
+
def initialize(command)
|
594
|
+
@command = command
|
595
|
+
end
|
596
|
+
|
597
|
+
extend Pipeline::ExpectResponseWithin::ClassMethods
|
598
|
+
|
599
|
+
@user_id_of_message_to_be_captured = USER_ID_HOLDER
|
600
|
+
self.timeframe_for_response = 200 # Second
|
601
|
+
|
602
|
+
|
603
|
+
def ALL_FALSE(*args)
|
604
|
+
args.all?(&:false?)
|
605
|
+
end
|
606
|
+
|
607
|
+
def ALL_FALSE_INSPECT(*args)
|
608
|
+
args.each_slice(2).map { |boolean, explanation|
|
609
|
+
"#{explanation}: #{boolean}"
|
610
|
+
}.join(' <> ')
|
611
|
+
end
|
612
|
+
|
613
|
+
|
614
|
+
def pump_once(&block)
|
615
|
+
count = 0
|
616
|
+
self.pump do
|
617
|
+
@stop_ladder = true if count > 0
|
618
|
+
|
619
|
+
|
620
|
+
if @stop_ladder
|
621
|
+
ladder(stop: @ladder_1)
|
622
|
+
else
|
623
|
+
block.call
|
624
|
+
count += 1
|
625
|
+
end
|
626
|
+
end
|
627
|
+
end
|
628
|
+
|
629
|
+
def pump(&block)
|
630
|
+
fail ERR_ID_2 if self.class.instance_variable_get(:@user_id_of_message_to_be_captured)[:gbot_id].nil?
|
631
|
+
|
632
|
+
|
633
|
+
gbot_id = self.class.instance_variable_get(:@user_id_of_message_to_be_captured)[:gbot_id]
|
634
|
+
|
635
|
+
message = nil
|
636
|
+
messages_by_gbot_in_timeframe = 0
|
637
|
+
@ladder_1 = ladder do |message_data|
|
638
|
+
|
639
|
+
puts message_data.inspect
|
640
|
+
|
641
|
+
puts ALL_FALSE_INSPECT(
|
642
|
+
message_data.nil?, "message_data.nil?",
|
643
|
+
FIRST_GBOT_MESSAGE_HOLDER[:first_gbot_message_id].nil?, "FIRST_GBOT_MESSAGE_HOLDER[:first_gbot_message_id].nil?",
|
644
|
+
message_data['id'] == FIRST_GBOT_MESSAGE_HOLDER[:first_gbot_message_id], "message_data['id'] == FIRST_GBOT_MESSAGE_HOLDER[:first_gbot_message_id]"
|
645
|
+
)
|
646
|
+
|
647
|
+
|
648
|
+
if ALL_FALSE(message_data.nil?, FIRST_GBOT_MESSAGE_HOLDER[:first_gbot_message_id].nil?, message_data['id'] == FIRST_GBOT_MESSAGE_HOLDER[:first_gbot_message_id])
|
649
|
+
fail ERR_ID_7 if message_data.nil?
|
650
|
+
fail ERR_ID_6 if FIRST_GBOT_MESSAGE_HOLDER[:first_gbot_message_id].nil?
|
651
|
+
fail ERR_ID_5 if message_data['id'] == FIRST_GBOT_MESSAGE_HOLDER[:first_gbot_message_id] # or fail ERR_ID_5
|
652
|
+
|
653
|
+
if message_data['author']['id'] == gbot_id
|
654
|
+
messages_by_gbot_in_timeframe += 1
|
655
|
+
|
656
|
+
message = message_data['content']
|
657
|
+
end
|
658
|
+
|
659
|
+
|
660
|
+
fail ERR_ID_3 if message.nil?
|
661
|
+
# next if message.nil?
|
662
|
+
fail ERR_ID_4 if messages_by_gbot_in_timeframe > 1
|
663
|
+
|
664
|
+
@message = message
|
665
|
+
|
666
|
+
puts "TEST TEST"
|
667
|
+
|
668
|
+
block.call
|
669
|
+
end
|
670
|
+
end
|
671
|
+
end
|
672
|
+
|
673
|
+
def response
|
674
|
+
@message
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
class GbotCommandForBot2Bot
|
679
|
+
def initialize(text, event)
|
680
|
+
@text = text
|
681
|
+
@event = event
|
682
|
+
end
|
683
|
+
|
684
|
+
def to_discord_message
|
685
|
+
"gbot: #{@text.to_s}"
|
686
|
+
end
|
687
|
+
|
688
|
+
def send
|
689
|
+
@event.respond(self.to_discord_message)
|
690
|
+
|
691
|
+
|
692
|
+
yield
|
693
|
+
end
|
694
|
+
end
|
695
|
+
end
|
696
|
+
|
697
|
+
|
698
|
+
|
699
|
+
ladder {}
|
700
|
+
|
701
|
+
EZIIDiscordIntegration::PipelineDiscordBot.new.bot.run
|
@@ -0,0 +1,14 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'ezii-discord'
|
3
|
+
s.version = '0.test'
|
4
|
+
s.date = '2019-10-23'
|
5
|
+
s.summary = "eZii Discord Integration RB"
|
6
|
+
s.description = "integrate eZii as a discord bot easily"
|
7
|
+
s.authors = ["Manuel Arno Korfmann"]
|
8
|
+
s.email = 'manu@korfmann.info'
|
9
|
+
s.files = Dir.glob("**/*")
|
10
|
+
s.homepage =
|
11
|
+
'https://google.com/?q=eZii'
|
12
|
+
s.license = 'MIT'
|
13
|
+
end
|
14
|
+
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module EZIIDiscordIntegration
|
2
|
+
class CurlManager
|
3
|
+
def initialize(website_urls)
|
4
|
+
@website_urls = website_urls.flatten
|
5
|
+
@threads = {}
|
6
|
+
end
|
7
|
+
|
8
|
+
def start_calls_in_background
|
9
|
+
@website_urls.each do |url|
|
10
|
+
# tst = -> { `curl #{CGI.escape(url)} -s -o /dev/null -w "%{time_starttransfer}\n"` }
|
11
|
+
#
|
12
|
+
# byebug
|
13
|
+
#
|
14
|
+
#
|
15
|
+
|
16
|
+
thread = Thread.new do
|
17
|
+
# §(INSECURE)
|
18
|
+
|
19
|
+
@threads[thread] = [`curl '#{url}' -s -o /dev/null -w "%{time_starttransfer}\n"`, url]
|
20
|
+
end
|
21
|
+
|
22
|
+
@threads[thread] = nil
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def wait_for_finish
|
27
|
+
@threads.keys.each(&:join)
|
28
|
+
|
29
|
+
return self
|
30
|
+
end
|
31
|
+
|
32
|
+
def winner
|
33
|
+
return @threads.values.min_by do |value|
|
34
|
+
fail ERR_ID_8 if !(value[0].to_f > 0)
|
35
|
+
value[0].to_f
|
36
|
+
end.inspect
|
37
|
+
end
|
38
|
+
|
39
|
+
def inspect
|
40
|
+
"""
|
41
|
+
EZIIDiscordIntegration::CurlManagers
|
42
|
+
Binding: #{binding}
|
43
|
+
File: #{__FILE__}
|
44
|
+
|
45
|
+
|
46
|
+
inspect of EZIIDiscordIntegration::CurlManagers# -> @website_urls (# is the symbol for an instance -> method edge in ruby)
|
47
|
+
|
48
|
+
|
49
|
+
#{@website_urls.inspect}
|
50
|
+
|
51
|
+
|
52
|
+
Threads
|
53
|
+
|
54
|
+
#{@threads.inspect}
|
55
|
+
"""
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
# @bot = ::Discordrb::Bot.new token: ENV['TEST_BOT_TOKEN']
|
2
|
+
|
3
|
+
|
4
|
+
# bot.message(with_text: 'pipeline:') do |event| # message must only cntain the text
|
5
|
+
#
|
6
|
+
#
|
7
|
+
# bot.message(content: '!pipeline gbot-id-capture') do |event| # message content must exactly match the content: value
|
8
|
+
# event.respond("Type start to begin")
|
9
|
+
# event.user.await(:start) do |start_event| # awaits any input by the user (or any user?)
|
10
|
+
# event.respond('gbot: get-id')
|
metadata
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ezii-discord
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.test
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Manuel Arno Korfmann
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-10-23 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: integrate eZii as a discord bot easily
|
14
|
+
email: manu@korfmann.info
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- Gemfile
|
20
|
+
- Gemfile.lock
|
21
|
+
- TUTORIAL.md
|
22
|
+
- chat-bot-1.rb
|
23
|
+
- ezii-discord-integration.gemspec
|
24
|
+
- lib/ezii_curl_manager.rb
|
25
|
+
- lib/test/test_ezii_curl_manager.rb
|
26
|
+
- test/test-chat-bot-1.rb
|
27
|
+
homepage: https://google.com/?q=eZii
|
28
|
+
licenses:
|
29
|
+
- MIT
|
30
|
+
metadata: {}
|
31
|
+
post_install_message:
|
32
|
+
rdoc_options: []
|
33
|
+
require_paths:
|
34
|
+
- lib
|
35
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">"
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
version: 1.3.1
|
45
|
+
requirements: []
|
46
|
+
rubygems_version: 3.0.3
|
47
|
+
signing_key:
|
48
|
+
specification_version: 4
|
49
|
+
summary: eZii Discord Integration RB
|
50
|
+
test_files: []
|